History

My first initial commit with all of mine experimental changes.

Dmitry Kabak (userdima committed 13 years ago

Commit d37b88d1 parent 3f5b46618352 files · +2598093 −-8690Browse files

Showing the changes to java/pkg/javax/sound/sampled/AudioSystem.java (1 of 18352 files). Show all

Unified · Split

java/pkg/javax/sound/sampled/AudioSystem.java+1631−0
@@ -0,0 +1,1631 @@
1+/*
2+ * Copyright (c) 1999, 2011, Oracle and/or its affiliates. All rights reserved.
3+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4+ *
5+ * This code is free software; you can redistribute it and/or modify it
6+ * under the terms of the GNU General Public License version 2 only, as
7+ * published by the Free Software Foundation. Oracle designates this
8+ * particular file as subject to the "Classpath" exception as provided
9+ * by Oracle in the LICENSE file that accompanied this code.
10+ *
11+ * This code is distributed in the hope that it will be useful, but WITHOUT
12+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
14+ * version 2 for more details (a copy is included in the LICENSE file that
15+ * accompanied this code).
16+ *
17+ * You should have received a copy of the GNU General Public License version
18+ * 2 along with this work; if not, write to the Free Software Foundation,
19+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20+ *
21+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22+ * or visit www.oracle.com if you need additional information or have any
23+ * questions.
24+ */
25+
26+package javax.sound.sampled;
27+
28+import java.io.File;
29+import java.io.InputStream;
30+import java.io.IOException;
31+import java.io.OutputStream;
32+import java.net.URL;
33+
34+import java.util.HashSet;
35+import java.util.List;
36+import java.util.Set;
37+import java.util.Vector;
38+import java.util.ArrayList;
39+
40+import javax.sound.sampled.spi.AudioFileWriter;
41+import javax.sound.sampled.spi.AudioFileReader;
42+import javax.sound.sampled.spi.FormatConversionProvider;
43+import javax.sound.sampled.spi.MixerProvider;
44+
45+import com.sun.media.sound.JDK13Services;
46+
47+/* $fb TODO:
48+ * - consistent usage of (typed) collections
49+ */
50+
51+
52+/**
53+ * The <code>AudioSystem</code> class acts as the entry point to the
54+ * sampled-audio system resources. This class lets you query and
55+ * access the mixers that are installed on the system.
56+ * <code>AudioSystem</code> includes a number of
57+ * methods for converting audio data between different formats, and for
58+ * translating between audio files and streams. It also provides a method
59+ * for obtaining a <code>{@link Line}</code> directly from the
60+ * <code>AudioSystem</code> without dealing explicitly
61+ * with mixers.
62+ *
63+ * <p>Properties can be used to specify the default mixer
64+ * for specific line types.
65+ * Both system properties and a properties file are considered.
66+ * In the Oracle reference implementation, the properties file is
67+ * &quot;lib/sound.properties&quot; in the JRE
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
70+ * specified, a suitable default is chosen among the available devices.
71+ * The syntax of the properties file is specified in
72+ * {@link java.util.Properties#load(InputStream) Properties.load}. The
73+ * following table lists the available property keys and which methods
74+ * consider them:
75+ *
76+ * <table border=0>
77+ * <tr>
78+ * <th>Property Key</th>
79+ * <th>Interface</th>
80+ * <th>Affected Method(s)</th>
81+ * </tr>
82+ * <tr>
83+ * <td><code>javax.sound.sampled.Clip</code></td>
84+ * <td>{@link Clip}</td>
85+ * <td>{@link #getLine}, {@link #getClip}</td>
86+ * </tr>
87+ * <tr>
88+ * <td><code>javax.sound.sampled.Port</code></td>
89+ * <td>{@link Port}</td>
90+ * <td>{@link #getLine}</td>
91+ * </tr>
92+ * <tr>
93+ * <td><code>javax.sound.sampled.SourceDataLine</code></td>
94+ * <td>{@link SourceDataLine}</td>
95+ * <td>{@link #getLine}, {@link #getSourceDataLine}</td>
96+ * </tr>
97+ * <tr>
98+ * <td><code>javax.sound.sampled.TargetDataLine</code></td>
99+ * <td>{@link TargetDataLine}</td>
100+ * <td>{@link #getLine}, {@link #getTargetDataLine}</td>
101+ * </tr>
102+ * </table>
103+ *
104+ * The property value consists of the provider class name
105+ * and the mixer name, separated by the hash mark (&quot;#&quot;).
106+ * The provider class name is the fully-qualified
107+ * name of a concrete {@link javax.sound.sampled.spi.MixerProvider
108+ * mixer provider} class. The mixer name is matched against
109+ * the <code>String</code> returned by the <code>getName</code>
110+ * method of <code>Mixer.Info</code>.
111+ * Either the class name, or the mixer name may be omitted.
112+ * If only the class name is specified, the trailing hash mark
113+ * is optional.
114+ *
115+ * <p>If the provider class is specified, and it can be
116+ * successully retrieved from the installed providers, the list of
117+ * <code>Mixer.Info</code> objects is retrieved
118+ * from the provider. Otherwise, or when these mixers
119+ * do not provide a subsequent match, the list is retrieved
120+ * from {@link #getMixerInfo} to contain
121+ * all available <code>Mixer.Info</code> objects.
122+ *
123+ * <p>If a mixer name is specified, the resulting list of
124+ * <code>Mixer.Info</code> objects is searched:
125+ * the first one with a matching name, and whose
126+ * <code>Mixer</code> provides the
127+ * respective line interface, will be returned.
128+ * If no matching <code>Mixer.Info</code> object
129+ * is found, or the mixer name is not specified,
130+ * the first mixer from the resulting
131+ * list, which provides the respective line
132+ * interface, will be returned.
133+ *
134+ * For example, the property <code>javax.sound.sampled.Clip</code>
135+ * with a value
136+ * <code>&quot;com.sun.media.sound.MixerProvider#SunClip&quot;</code>
137+ * will have the following consequences when
138+ * <code>getLine</code> is called requesting a <code>Clip</code>
139+ * instance:
140+ * if the class <code>com.sun.media.sound.MixerProvider</code> exists
141+ * in the list of installed mixer providers,
142+ * the first <code>Clip</code> from the first mixer with name
143+ * <code>&quot;SunClip&quot;</code> will be returned. If it cannot
144+ * be found, the first <code>Clip</code> from the first mixer
145+ * of the specified provider will be returned, regardless of name.
146+ * If there is none, the first <code>Clip</code> from the first
147+ * <code>Mixer</code> with name
148+ * <code>&quot;SunClip&quot;</code> in the list of all mixers
149+ * (as returned by <code>getMixerInfo</code>) will be returned,
150+ * or, if not found, the first <code>Clip</code> of the first
151+ * <code>Mixer</code>that can be found in the list of all
152+ * mixers is returned.
153+ * If that fails, too, an <code>IllegalArgumentException</code>
154+ * is thrown.
155+ *
156+ * @author Kara Kytle
157+ * @author Florian Bomers
158+ * @author Matthias Pfisterer
159+ * @author Kevin P. Smith
160+ *
161+ * @see AudioFormat
162+ * @see AudioInputStream
163+ * @see Mixer
164+ * @see Line
165+ * @see Line.Info
166+ * @since 1.3
167+ */
168+public class AudioSystem {
169+
170+ /**
171+ * An integer that stands for an unknown numeric value.
172+ * This value is appropriate only for signed quantities that do not
173+ * normally take negative values. Examples include file sizes, frame
174+ * sizes, buffer sizes, and sample rates.
175+ * A number of Java Sound constructors accept
176+ * a value of <code>NOT_SPECIFIED</code> for such parameters. Other
177+ * methods may also accept or return this value, as documented.
178+ */
179+ public static final int NOT_SPECIFIED = -1;
180+
181+ /**
182+ * Private no-args constructor for ensuring against instantiation.
183+ */
184+ private AudioSystem() {
185+ }
186+
187+
188+ /**
189+ * Obtains an array of mixer info objects that represents
190+ * the set of audio mixers that are currently installed on the system.
191+ * @return an array of info objects for the currently installed mixers. If no mixers
192+ * are available on the system, an array of length 0 is returned.
193+ * @see #getMixer
194+ */
195+ public static Mixer.Info[] getMixerInfo() {
196+
197+ List infos = getMixerInfoList();
198+ Mixer.Info[] allInfos = (Mixer.Info[]) infos.toArray(new Mixer.Info[infos.size()]);
199+ return allInfos;
200+ }
201+
202+
203+ /**
204+ * Obtains the requested audio mixer.
205+ * @param info a <code>Mixer.Info</code> object representing the desired
206+ * mixer, or <code>null</code> for the system default mixer
207+ * @return the requested mixer
208+ * @throws SecurityException if the requested mixer
209+ * is unavailable because of security restrictions
210+ * @throws IllegalArgumentException if the info object does not represent
211+ * a mixer installed on the system
212+ * @see #getMixerInfo
213+ */
214+ public static Mixer getMixer(Mixer.Info info) {
215+
216+ Mixer mixer = null;
217+ List providers = getMixerProviders();
218+
219+ for(int i = 0; i < providers.size(); i++ ) {
220+
221+ try {
222+ return ((MixerProvider)providers.get(i)).getMixer(info);
223+
224+ } catch (IllegalArgumentException e) {
225+ } catch (NullPointerException e) {
226+ // $$jb 08.20.99: If the strings in the info object aren't
227+ // set, then Netscape (using jdk1.1.5) tends to throw
228+ // NPE's when doing some string manipulation. This is
229+ // probably not the best fix, but is solves the problem
230+ // of the NPE in Netscape using local classes
231+ // $$jb 11.01.99: Replacing this patch.
232+ }
233+ }
234+
235+ //$$fb if looking for default mixer, and not found yet, add a round of looking
236+ if (info == null) {
237+ for(int i = 0; i < providers.size(); i++ ) {
238+ try {
239+ MixerProvider provider = (MixerProvider) providers.get(i);
240+ Mixer.Info[] infos = provider.getMixerInfo();
241+ // start from 0 to last device (do not reverse this order)
242+ for (int ii = 0; ii < infos.length; ii++) {
243+ try {
244+ return provider.getMixer(infos[ii]);
245+ } catch (IllegalArgumentException e) {
246+ // this is not a good default device :)
247+ }
248+ }
249+ } catch (IllegalArgumentException e) {
250+ } catch (NullPointerException e) {
251+ }
252+ }
253+ }
254+
255+
256+ throw new IllegalArgumentException("Mixer not supported: "
257+ + (info!=null?info.toString():"null"));
258+ }
259+
260+
261+ //$$fb 2002-11-26: fix for 4757930: DOC: AudioSystem.getTarget/SourceLineInfo() is ambiguous
262+ /**
263+ * Obtains information about all source lines of a particular type that are supported
264+ * by the installed mixers.
265+ * @param info a <code>Line.Info</code> object that specifies the kind of
266+ * lines about which information is requested
267+ * @return an array of <code>Line.Info</code> objects describing source lines matching
268+ * the type requested. If no matching source lines are supported, an array of length 0
269+ * is returned.
270+ *
271+ * @see Mixer#getSourceLineInfo(Line.Info)
272+ */
273+ public static Line.Info[] getSourceLineInfo(Line.Info info) {
274+
275+ Vector vector = new Vector();
276+ Line.Info[] currentInfoArray;
277+
278+ Mixer mixer;
279+ Line.Info fullInfo = null;
280+ Mixer.Info[] infoArray = getMixerInfo();
281+
282+ for (int i = 0; i < infoArray.length; i++) {
283+
284+ mixer = getMixer(infoArray[i]);
285+
286+ currentInfoArray = mixer.getSourceLineInfo(info);
287+ for (int j = 0; j < currentInfoArray.length; j++) {
288+ vector.addElement(currentInfoArray[j]);
289+ }
290+ }
291+
292+ Line.Info[] returnedArray = new Line.Info[vector.size()];
293+
294+ for (int i = 0; i < returnedArray.length; i++) {
295+ returnedArray[i] = (Line.Info)vector.get(i);
296+ }
297+
298+ return returnedArray;
299+ }
300+
301+
302+ /**
303+ * Obtains information about all target lines of a particular type that are supported
304+ * by the installed mixers.
305+ * @param info a <code>Line.Info</code> object that specifies the kind of
306+ * lines about which information is requested
307+ * @return an array of <code>Line.Info</code> objects describing target lines matching
308+ * the type requested. If no matching target lines are supported, an array of length 0
309+ * is returned.
310+ *
311+ * @see Mixer#getTargetLineInfo(Line.Info)
312+ */
313+ public static Line.Info[] getTargetLineInfo(Line.Info info) {
314+
315+ Vector vector = new Vector();
316+ Line.Info[] currentInfoArray;
317+
318+ Mixer mixer;
319+ Line.Info fullInfo = null;
320+ Mixer.Info[] infoArray = getMixerInfo();
321+
322+ for (int i = 0; i < infoArray.length; i++) {
323+
324+ mixer = getMixer(infoArray[i]);
325+
326+ currentInfoArray = mixer.getTargetLineInfo(info);
327+ for (int j = 0; j < currentInfoArray.length; j++) {
328+ vector.addElement(currentInfoArray[j]);
329+ }
330+ }
331+
332+ Line.Info[] returnedArray = new Line.Info[vector.size()];
333+
334+ for (int i = 0; i < returnedArray.length; i++) {
335+ returnedArray[i] = (Line.Info)vector.get(i);
336+ }
337+
338+ return returnedArray;
339+ }
340+
341+
342+ /**
343+ * Indicates whether the system supports any lines that match
344+ * the specified <code>Line.Info</code> object. A line is supported if
345+ * any installed mixer supports it.
346+ * @param info a <code>Line.Info</code> object describing the line for which support is queried
347+ * @return <code>true</code> if at least one matching line is
348+ * supported, otherwise <code>false</code>
349+ *
350+ * @see Mixer#isLineSupported(Line.Info)
351+ */
352+ public static boolean isLineSupported(Line.Info info) {
353+
354+ Mixer mixer;
355+ Mixer.Info[] infoArray = getMixerInfo();
356+
357+ for (int i = 0; i < infoArray.length; i++) {
358+
359+ if( infoArray[i] != null ) {
360+ mixer = getMixer(infoArray[i]);
361+ if (mixer.isLineSupported(info)) {
362+ return true;
363+ }
364+ }
365+ }
366+
367+ return false;
368+ }
369+
370+ /**
371+ * Obtains a line that matches the description in the specified
372+ * <code>Line.Info</code> object.
373+ *
374+ * <p>If a <code>DataLine</code> is requested, and <code>info</code>
375+ * is an instance of <code>DataLine.Info</code> specifying at least
376+ * one fully qualified audio format, the last one
377+ * will be used as the default format of the returned
378+ * <code>DataLine</code>.
379+ *
380+ * <p>If system properties
381+ * <code>javax.sound.sampled.Clip</code>,
382+ * <code>javax.sound.sampled.Port</code>,
383+ * <code>javax.sound.sampled.SourceDataLine</code> and
384+ * <code>javax.sound.sampled.TargetDataLine</code> are defined
385+ * or they are defined in the file &quot;sound.properties&quot;,
386+ * they are used to retrieve default lines.
387+ * For details, refer to the {@link AudioSystem class description}.
388+ *
389+ * If the respective property is not set, or the mixer
390+ * requested in the property is not installed or does not provide the
391+ * requested line, all installed mixers are queried for the
392+ * requested line type. A Line will be returned from the first mixer
393+ * providing the requested line type.
394+ *
395+ * @param info a <code>Line.Info</code> object describing the desired kind of line
396+ * @return a line of the requested kind
397+ *
398+ * @throws LineUnavailableException if a matching line
399+ * is not available due to resource restrictions
400+ * @throws SecurityException if a matching line
401+ * is not available due to security restrictions
402+ * @throws IllegalArgumentException if the system does not
403+ * support at least one line matching the specified
404+ * <code>Line.Info</code> object
405+ * through any installed mixer
406+ */
407+ public static Line getLine(Line.Info info) throws LineUnavailableException {
408+ LineUnavailableException lue = null;
409+ List providers = getMixerProviders();
410+
411+
412+ // 1: try from default mixer for this line class
413+ try {
414+ Mixer mixer = getDefaultMixer(providers, info);
415+ if (mixer != null && mixer.isLineSupported(info)) {
416+ return mixer.getLine(info);
417+ }
418+ } catch (LineUnavailableException e) {
419+ lue = e;
420+ } catch (IllegalArgumentException iae) {
421+ // must not happen... but better to catch it here,
422+ // if plug-ins are badly written
423+ }
424+
425+
426+ // 2: if that doesn't work, try to find any mixing mixer
427+ for(int i = 0; i < providers.size(); i++) {
428+ MixerProvider provider = (MixerProvider) providers.get(i);
429+ Mixer.Info[] infos = provider.getMixerInfo();
430+
431+ for (int j = 0; j < infos.length; j++) {
432+ try {
433+ Mixer mixer = provider.getMixer(infos[j]);
434+ // see if this is an appropriate mixer which can mix
435+ if (isAppropriateMixer(mixer, info, true)) {
436+ return mixer.getLine(info);
437+ }
438+ } catch (LineUnavailableException e) {
439+ lue = e;
440+ } catch (IllegalArgumentException iae) {
441+ // must not happen... but better to catch it here,
442+ // if plug-ins are badly written
443+ }
444+ }
445+ }
446+
447+
448+ // 3: if that didn't work, try to find any non-mixing mixer
449+ for(int i = 0; i < providers.size(); i++) {
450+ MixerProvider provider = (MixerProvider) providers.get(i);
451+ Mixer.Info[] infos = provider.getMixerInfo();
452+ for (int j = 0; j < infos.length; j++) {
453+ try {
454+ Mixer mixer = provider.getMixer(infos[j]);
455+ // see if this is an appropriate mixer which can mix
456+ if (isAppropriateMixer(mixer, info, false)) {
457+ return mixer.getLine(info);
458+ }
459+ } catch (LineUnavailableException e) {
460+ lue = e;
461+ } catch (IllegalArgumentException iae) {
462+ // must not happen... but better to catch it here,
463+ // if plug-ins are badly written
464+ }
465+ }
466+ }
467+
468+ // if this line was supported but was not available, throw the last
469+ // LineUnavailableException we got (??).
470+ if (lue != null) {
471+ throw lue;
472+ }
473+
474+ // otherwise, the requested line was not supported, so throw
475+ // an Illegal argument exception
476+ throw new IllegalArgumentException("No line matching " +
477+ info.toString() + " is supported.");
478+ }
479+
480+
481+ /**
482+ * Obtains a clip that can be used for playing back
483+ * an audio file or an audio stream. The returned clip
484+ * will be provided by the default system mixer, or,
485+ * if not possible, by any other mixer installed in the
486+ * system that supports a <code>Clip</code>
487+ * object.
488+ *
489+ * <p>The returned clip must be opened with the
490+ * <code>open(AudioFormat)</code> or
491+ * <code>open(AudioInputStream)</code> method.
492+ *
493+ * <p>This is a high-level method that uses <code>getMixer</code>
494+ * and <code>getLine</code> internally.
495+ *
496+ * <p>If the system property
497+ * <code>javax.sound.sampled.Clip</code>
498+ * is defined or it is defined in the file &quot;sound.properties&quot;,
499+ * it is used to retrieve the default clip.
500+ * For details, refer to the {@link AudioSystem class description}.
501+ *
502+ * @return the desired clip object
503+ *
504+ * @throws LineUnavailableException if a clip object
505+ * is not available due to resource restrictions
506+ * @throws SecurityException if a clip object
507+ * is not available due to security restrictions
508+ * @throws IllegalArgumentException if the system does not
509+ * support at least one clip instance through any installed mixer
510+ *
511+ * @see #getClip(Mixer.Info)
512+ * @since 1.5
513+ */
514+ public static Clip getClip() throws LineUnavailableException{
515+ AudioFormat format = new AudioFormat(AudioFormat.Encoding.PCM_SIGNED,
516+ AudioSystem.NOT_SPECIFIED,
517+ 16, 2, 4,
518+ AudioSystem.NOT_SPECIFIED, true);
519+ DataLine.Info info = new DataLine.Info(Clip.class, format);
520+ return (Clip) AudioSystem.getLine(info);
521+ }
522+
523+
524+ /**
525+ * Obtains a clip from the specified mixer that can be
526+ * used for playing back an audio file or an audio stream.
527+ *
528+ * <p>The returned clip must be opened with the
529+ * <code>open(AudioFormat)</code> or
530+ * <code>open(AudioInputStream)</code> method.
531+ *
532+ * <p>This is a high-level method that uses <code>getMixer</code>
533+ * and <code>getLine</code> internally.
534+ *
535+ * @param mixerInfo a <code>Mixer.Info</code> object representing the
536+ * desired mixer, or <code>null</code> for the system default mixer
537+ * @return a clip object from the specified mixer
538+ *
539+ * @throws LineUnavailableException if a clip
540+ * is not available from this mixer due to resource restrictions
541+ * @throws SecurityException if a clip
542+ * is not available from this mixer due to security restrictions
543+ * @throws IllegalArgumentException if the system does not
544+ * support at least one clip through the specified mixer
545+ *
546+ * @see #getClip()
547+ * @since 1.5
548+ */
549+ public static Clip getClip(Mixer.Info mixerInfo) throws LineUnavailableException{
550+ AudioFormat format = new AudioFormat(AudioFormat.Encoding.PCM_SIGNED,
551+ AudioSystem.NOT_SPECIFIED,
552+ 16, 2, 4,
553+ AudioSystem.NOT_SPECIFIED, true);
554+ DataLine.Info info = new DataLine.Info(Clip.class, format);
555+ Mixer mixer = AudioSystem.getMixer(mixerInfo);
556+ return (Clip) mixer.getLine(info);
557+ }
558+
559+
560+ /**
561+ * Obtains a source data line that can be used for playing back
562+ * audio data in the format specified by the
563+ * <code>AudioFormat</code> object. The returned line
564+ * will be provided by the default system mixer, or,
565+ * if not possible, by any other mixer installed in the
566+ * system that supports a matching
567+ * <code>SourceDataLine</code> object.
568+ *
569+ * <p>The returned line should be opened with the
570+ * <code>open(AudioFormat)</code> or
571+ * <code>open(AudioFormat, int)</code> method.
572+ *
573+ * <p>This is a high-level method that uses <code>getMixer</code>
574+ * and <code>getLine</code> internally.
575+ *
576+ * <p>The returned <code>SourceDataLine</code>'s default
577+ * audio format will be initialized with <code>format</code>.
578+ *
579+ * <p>If the system property
580+ * <code>javax.sound.sampled.SourceDataLine</code>
581+ * is defined or it is defined in the file &quot;sound.properties&quot;,
582+ * it is used to retrieve the default source data line.
583+ * For details, refer to the {@link AudioSystem class description}.
584+ *
585+ * @param format an <code>AudioFormat</code> object specifying
586+ * the supported audio format of the returned line,
587+ * or <code>null</code> for any audio format
588+ * @return the desired <code>SourceDataLine</code> object
589+ *
590+ * @throws LineUnavailableException if a matching source data line
591+ * is not available due to resource restrictions
592+ * @throws SecurityException if a matching source data line
593+ * is not available due to security restrictions
594+ * @throws IllegalArgumentException if the system does not
595+ * support at least one source data line supporting the
596+ * specified audio format through any installed mixer
597+ *
598+ * @see #getSourceDataLine(AudioFormat, Mixer.Info)
599+ * @since 1.5
600+ */
601+ public static SourceDataLine getSourceDataLine(AudioFormat format)
602+ throws LineUnavailableException{
603+ DataLine.Info info = new DataLine.Info(SourceDataLine.class, format);
604+ return (SourceDataLine) AudioSystem.getLine(info);
605+ }
606+
607+
608+ /**
609+ * Obtains a source data line that can be used for playing back
610+ * audio data in the format specified by the
611+ * <code>AudioFormat</code> object, provided by the mixer
612+ * specified by the <code>Mixer.Info</code> object.
613+ *
614+ * <p>The returned line should be opened with the
615+ * <code>open(AudioFormat)</code> or
616+ * <code>open(AudioFormat, int)</code> method.
617+ *
618+ * <p>This is a high-level method that uses <code>getMixer</code>
619+ * and <code>getLine</code> internally.
620+ *
621+ * <p>The returned <code>SourceDataLine</code>'s default
622+ * audio format will be initialized with <code>format</code>.
623+ *
624+ * @param format an <code>AudioFormat</code> object specifying
625+ * the supported audio format of the returned line,
626+ * or <code>null</code> for any audio format
627+ * @param mixerinfo a <code>Mixer.Info</code> object representing
628+ * the desired mixer, or <code>null</code> for the system
629+ * default mixer
630+ * @return the desired <code>SourceDataLine</code> object
631+ *
632+ * @throws LineUnavailableException if a matching source data
633+ * line is not available from the specified mixer due
634+ * to resource restrictions
635+ * @throws SecurityException if a matching source data line
636+ * is not available from the specified mixer due to
637+ * security restrictions
638+ * @throws IllegalArgumentException if the specified mixer does
639+ * not support at least one source data line supporting
640+ * the specified audio format
641+ *
642+ * @see #getSourceDataLine(AudioFormat)
643+ * @since 1.5
644+ */
645+ public static SourceDataLine getSourceDataLine(AudioFormat format,
646+ Mixer.Info mixerinfo)
647+ throws LineUnavailableException{
648+ DataLine.Info info = new DataLine.Info(SourceDataLine.class, format);
649+ Mixer mixer = AudioSystem.getMixer(mixerinfo);
650+ return (SourceDataLine) mixer.getLine(info);
651+ }
652+
653+
654+ /**
655+ * Obtains a target data line that can be used for recording
656+ * audio data in the format specified by the
657+ * <code>AudioFormat</code> object. The returned line
658+ * will be provided by the default system mixer, or,
659+ * if not possible, by any other mixer installed in the
660+ * system that supports a matching
661+ * <code>TargetDataLine</code> object.
662+ *
663+ * <p>The returned line should be opened with the
664+ * <code>open(AudioFormat)</code> or
665+ * <code>open(AudioFormat, int)</code> method.
666+ *
667+ * <p>This is a high-level method that uses <code>getMixer</code>
668+ * and <code>getLine</code> internally.
669+ *
670+ * <p>The returned <code>TargetDataLine</code>'s default
671+ * audio format will be initialized with <code>format</code>.
672+ *
673+ * <p>If the system property
674+ * {@code javax.sound.sampled.TargetDataLine}
675+ * is defined or it is defined in the file &quot;sound.properties&quot;,
676+ * it is used to retrieve the default target data line.
677+ * For details, refer to the {@link AudioSystem class description}.
678+ *
679+ * @param format an <code>AudioFormat</code> object specifying
680+ * the supported audio format of the returned line,
681+ * or <code>null</code> for any audio format
682+ * @return the desired <code>TargetDataLine</code> object
683+ *
684+ * @throws LineUnavailableException if a matching target data line
685+ * is not available due to resource restrictions
686+ * @throws SecurityException if a matching target data line
687+ * is not available due to security restrictions
688+ * @throws IllegalArgumentException if the system does not
689+ * support at least one target data line supporting the
690+ * specified audio format through any installed mixer
691+ *
692+ * @see #getTargetDataLine(AudioFormat, Mixer.Info)
693+ * @see AudioPermission
694+ * @since 1.5
695+ */
696+ public static TargetDataLine getTargetDataLine(AudioFormat format)
697+ throws LineUnavailableException{
698+
699+ DataLine.Info info = new DataLine.Info(TargetDataLine.class, format);
700+ return (TargetDataLine) AudioSystem.getLine(info);
701+ }
702+
703+
704+
705+ /**
706+ * Obtains a target data line that can be used for recording
707+ * audio data in the format specified by the
708+ * <code>AudioFormat</code> object, provided by the mixer
709+ * specified by the <code>Mixer.Info</code> object.
710+ *
711+ * <p>The returned line should be opened with the
712+ * <code>open(AudioFormat)</code> or
713+ * <code>open(AudioFormat, int)</code> method.
714+ *
715+ * <p>This is a high-level method that uses <code>getMixer</code>
716+ * and <code>getLine</code> internally.
717+ *
718+ * <p>The returned <code>TargetDataLine</code>'s default
719+ * audio format will be initialized with <code>format</code>.
720+ *
721+ * @param format an <code>AudioFormat</code> object specifying
722+ * the supported audio format of the returned line,
723+ * or <code>null</code> for any audio format
724+ * @param mixerinfo a <code>Mixer.Info</code> object representing the
725+ * desired mixer, or <code>null</code> for the system default mixer
726+ * @return the desired <code>TargetDataLine</code> object
727+ *
728+ * @throws LineUnavailableException if a matching target data
729+ * line is not available from the specified mixer due
730+ * to resource restrictions
731+ * @throws SecurityException if a matching target data line
732+ * is not available from the specified mixer due to
733+ * security restrictions
734+ * @throws IllegalArgumentException if the specified mixer does
735+ * not support at least one target data line supporting
736+ * the specified audio format
737+ *
738+ * @see #getTargetDataLine(AudioFormat)
739+ * @see AudioPermission
740+ * @since 1.5
741+ */
742+ public static TargetDataLine getTargetDataLine(AudioFormat format,
743+ Mixer.Info mixerinfo)
744+ throws LineUnavailableException {
745+
746+ DataLine.Info info = new DataLine.Info(TargetDataLine.class, format);
747+ Mixer mixer = AudioSystem.getMixer(mixerinfo);
748+ return (TargetDataLine) mixer.getLine(info);
749+ }
750+
751+
752+ // $$fb 2002-04-12: fix for 4662082: behavior of AudioSystem.getTargetEncodings() methods doesn't match the spec
753+ /**
754+ * Obtains the encodings that the system can obtain from an
755+ * audio input stream with the specified encoding using the set
756+ * of installed format converters.
757+ * @param sourceEncoding the encoding for which conversion support
758+ * is queried
759+ * @return array of encodings. If <code>sourceEncoding</code>is not supported,
760+ * an array of length 0 is returned. Otherwise, the array will have a length
761+ * of at least 1, representing <code>sourceEncoding</code> (no conversion).
762+ */
763+ public static AudioFormat.Encoding[] getTargetEncodings(AudioFormat.Encoding sourceEncoding) {
764+
765+ List codecs = getFormatConversionProviders();
766+ Vector encodings = new Vector();
767+
768+ AudioFormat.Encoding encs[] = null;
769+
770+ // gather from all the codecs
771+ for(int i=0; i<codecs.size(); i++ ) {
772+ FormatConversionProvider codec = (FormatConversionProvider) codecs.get(i);
773+ if( codec.isSourceEncodingSupported( sourceEncoding ) ) {
774+ encs = codec.getTargetEncodings();
775+ for (int j = 0; j < encs.length; j++) {
776+ encodings.addElement( encs[j] );
777+ }
778+ }
779+ }
780+ AudioFormat.Encoding encs2[] = (AudioFormat.Encoding[]) encodings.toArray(new AudioFormat.Encoding[0]);
781+ return encs2;
782+ }
783+
784+
785+
786+ // $$fb 2002-04-12: fix for 4662082: behavior of AudioSystem.getTargetEncodings() methods doesn't match the spec
787+ /**
788+ * Obtains the encodings that the system can obtain from an
789+ * audio input stream with the specified format using the set
790+ * of installed format converters.
791+ * @param sourceFormat the audio format for which conversion
792+ * is queried
793+ * @return array of encodings. If <code>sourceFormat</code>is not supported,
794+ * an array of length 0 is returned. Otherwise, the array will have a length
795+ * of at least 1, representing the encoding of <code>sourceFormat</code> (no conversion).
796+ */
797+ public static AudioFormat.Encoding[] getTargetEncodings(AudioFormat sourceFormat) {
798+
799+
800+ List codecs = getFormatConversionProviders();
801+ Vector encodings = new Vector();
802+
803+ int size = 0;
804+ int index = 0;
805+ AudioFormat.Encoding encs[] = null;
806+
807+ // gather from all the codecs
808+
809+ for(int i=0; i<codecs.size(); i++ ) {
810+ encs = ((FormatConversionProvider) codecs.get(i)).getTargetEncodings(sourceFormat);
811+ size += encs.length;
812+ encodings.addElement( encs );
813+ }
814+
815+ // now build a new array
816+
817+ AudioFormat.Encoding encs2[] = new AudioFormat.Encoding[size];
818+ for(int i=0; i<encodings.size(); i++ ) {
819+ encs = (AudioFormat.Encoding [])(encodings.get(i));
820+ for(int j=0; j<encs.length; j++ ) {
821+ encs2[index++] = encs[j];
822+ }
823+ }
824+ return encs2;
825+ }
826+
827+
828+ /**
829+ * Indicates whether an audio input stream of the specified encoding
830+ * can be obtained from an audio input stream that has the specified
831+ * format.
832+ * @param targetEncoding the desired encoding after conversion
833+ * @param sourceFormat the audio format before conversion
834+ * @return <code>true</code> if the conversion is supported,
835+ * otherwise <code>false</code>
836+ */
837+ public static boolean isConversionSupported(AudioFormat.Encoding targetEncoding, AudioFormat sourceFormat) {
838+
839+
840+ List codecs = getFormatConversionProviders();
841+
842+ for(int i=0; i<codecs.size(); i++ ) {
843+ FormatConversionProvider codec = (FormatConversionProvider) codecs.get(i);
844+ if(codec.isConversionSupported(targetEncoding,sourceFormat) ) {
845+ return true;
846+ }
847+ }
848+ return false;
849+ }
850+
851+
852+ /**
853+ * Obtains an audio input stream of the indicated encoding, by converting the
854+ * provided audio input stream.
855+ * @param targetEncoding the desired encoding after conversion
856+ * @param sourceStream the stream to be converted
857+ * @return an audio input stream of the indicated encoding
858+ * @throws IllegalArgumentException if the conversion is not supported
859+ * @see #getTargetEncodings(AudioFormat.Encoding)
860+ * @see #getTargetEncodings(AudioFormat)
861+ * @see #isConversionSupported(AudioFormat.Encoding, AudioFormat)
862+ * @see #getAudioInputStream(AudioFormat, AudioInputStream)
863+ */
864+ public static AudioInputStream getAudioInputStream(AudioFormat.Encoding targetEncoding,
865+ AudioInputStream sourceStream) {
866+
867+ List codecs = getFormatConversionProviders();
868+
869+ for(int i = 0; i < codecs.size(); i++) {
870+ FormatConversionProvider codec = (FormatConversionProvider) codecs.get(i);
871+ if( codec.isConversionSupported( targetEncoding, sourceStream.getFormat() ) ) {
872+ return codec.getAudioInputStream( targetEncoding, sourceStream );
873+ }
874+ }
875+ // we ran out of options, throw an exception
876+ throw new IllegalArgumentException("Unsupported conversion: " + targetEncoding + " from " + sourceStream.getFormat());
877+ }
878+
879+
880+ /**
881+ * Obtains the formats that have a particular encoding and that the system can
882+ * obtain from a stream of the specified format using the set of
883+ * installed format converters.
884+ * @param targetEncoding the desired encoding after conversion
885+ * @param sourceFormat the audio format before conversion
886+ * @return array of formats. If no formats of the specified
887+ * encoding are supported, an array of length 0 is returned.
888+ */
889+ public static AudioFormat[] getTargetFormats(AudioFormat.Encoding targetEncoding, AudioFormat sourceFormat) {
890+
891+ List codecs = getFormatConversionProviders();
892+ Vector formats = new Vector();
893+
894+ int size = 0;
895+ int index = 0;
896+ AudioFormat fmts[] = null;
897+
898+ // gather from all the codecs
899+
900+ for(int i=0; i<codecs.size(); i++ ) {
901+ FormatConversionProvider codec = (FormatConversionProvider) codecs.get(i);
902+ fmts = codec.getTargetFormats(targetEncoding, sourceFormat);
903+ size += fmts.length;
904+ formats.addElement( fmts );
905+ }
906+
907+ // now build a new array
908+
909+ AudioFormat fmts2[] = new AudioFormat[size];
910+ for(int i=0; i<formats.size(); i++ ) {
911+ fmts = (AudioFormat [])(formats.get(i));
912+ for(int j=0; j<fmts.length; j++ ) {
913+ fmts2[index++] = fmts[j];
914+ }
915+ }
916+ return fmts2;
917+ }
918+
919+
920+ /**
921+ * Indicates whether an audio input stream of a specified format
922+ * can be obtained from an audio input stream of another specified format.
923+ * @param targetFormat the desired audio format after conversion
924+ * @param sourceFormat the audio format before conversion
925+ * @return <code>true</code> if the conversion is supported,
926+ * otherwise <code>false</code>
927+ */
928+
929+ public static boolean isConversionSupported(AudioFormat targetFormat, AudioFormat sourceFormat) {
930+
931+ List codecs = getFormatConversionProviders();
932+
933+ for(int i=0; i<codecs.size(); i++ ) {
934+ FormatConversionProvider codec = (FormatConversionProvider) codecs.get(i);
935+ if(codec.isConversionSupported(targetFormat, sourceFormat) ) {
936+ return true;
937+ }
938+ }
939+ return false;
940+ }
941+
942+
943+ /**
944+ * Obtains an audio input stream of the indicated format, by converting the
945+ * provided audio input stream.
946+ * @param targetFormat the desired audio format after conversion
947+ * @param sourceStream the stream to be converted
948+ * @return an audio input stream of the indicated format
949+ * @throws IllegalArgumentException if the conversion is not supported
950+ * #see #getTargetEncodings(AudioFormat)
951+ * @see #getTargetFormats(AudioFormat.Encoding, AudioFormat)
952+ * @see #isConversionSupported(AudioFormat, AudioFormat)
953+ * @see #getAudioInputStream(AudioFormat.Encoding, AudioInputStream)
954+ */
955+ public static AudioInputStream getAudioInputStream(AudioFormat targetFormat,
956+ AudioInputStream sourceStream) {
957+
958+ if (sourceStream.getFormat().matches(targetFormat)) {
959+ return sourceStream;
960+ }
961+
962+ List codecs = getFormatConversionProviders();
963+
964+ for(int i = 0; i < codecs.size(); i++) {
965+ FormatConversionProvider codec = (FormatConversionProvider) codecs.get(i);
966+ if(codec.isConversionSupported(targetFormat,sourceStream.getFormat()) ) {
967+ return codec.getAudioInputStream(targetFormat,sourceStream);
968+ }
969+ }
970+
971+ // we ran out of options...
972+ throw new IllegalArgumentException("Unsupported conversion: " + targetFormat + " from " + sourceStream.getFormat());
973+ }
974+
975+
976+ /**
977+ * Obtains the audio file format of the provided input stream. The stream must
978+ * point to valid audio file data. The implementation of this method may require
979+ * multiple parsers to examine the stream to determine whether they support it.
980+ * These parsers must be able to mark the stream, read enough data to determine whether they
981+ * support the stream, and, if not, reset the stream's read pointer to its original
982+ * position. If the input stream does not support these operations, this method may fail
983+ * with an <code>IOException</code>.
984+ * @param stream the input stream from which file format information should be
985+ * extracted
986+ * @return an <code>AudioFileFormat</code> object describing the stream's audio file format
987+ * @throws UnsupportedAudioFileException if the stream does not point to valid audio
988+ * file data recognized by the system
989+ * @throws IOException if an input/output exception occurs
990+ * @see InputStream#markSupported
991+ * @see InputStream#mark
992+ */
993+ public static AudioFileFormat getAudioFileFormat(InputStream stream)
994+ throws UnsupportedAudioFileException, IOException {
995+
996+ List providers = getAudioFileReaders();
997+ AudioFileFormat format = null;
998+
999+ for(int i = 0; i < providers.size(); i++ ) {
1000+ AudioFileReader reader = (AudioFileReader) providers.get(i);
1001+ try {
1002+ format = reader.getAudioFileFormat( stream ); // throws IOException
1003+ break;
1004+ } catch (UnsupportedAudioFileException e) {
1005+ continue;
1006+ }
1007+ }
1008+
1009+ if( format==null ) {
1010+ throw new UnsupportedAudioFileException("file is not a supported file type");
1011+ } else {
1012+ return format;
1013+ }
1014+ }
1015+
1016+ /**
1017+ * Obtains the audio file format of the specified URL. The URL must
1018+ * point to valid audio file data.
1019+ * @param url the URL from which file format information should be
1020+ * extracted
1021+ * @return an <code>AudioFileFormat</code> object describing the audio file format
1022+ * @throws UnsupportedAudioFileException if the URL does not point to valid audio
1023+ * file data recognized by the system
1024+ * @throws IOException if an input/output exception occurs
1025+ */
1026+ public static AudioFileFormat getAudioFileFormat(URL url)
1027+ throws UnsupportedAudioFileException, IOException {
1028+
1029+ List providers = getAudioFileReaders();
1030+ AudioFileFormat format = null;
1031+
1032+ for(int i = 0; i < providers.size(); i++ ) {
1033+ AudioFileReader reader = (AudioFileReader) providers.get(i);
1034+ try {
1035+ format = reader.getAudioFileFormat( url ); // throws IOException
1036+ break;
1037+ } catch (UnsupportedAudioFileException e) {
1038+ continue;
1039+ }
1040+ }
1041+
1042+ if( format==null ) {
1043+ throw new UnsupportedAudioFileException("file is not a supported file type");
1044+ } else {
1045+ return format;
1046+ }
1047+ }
1048+
1049+ /**
1050+ * Obtains the audio file format of the specified <code>File</code>. The <code>File</code> must
1051+ * point to valid audio file data.
1052+ * @param file the <code>File</code> from which file format information should be
1053+ * extracted
1054+ * @return an <code>AudioFileFormat</code> object describing the audio file format
1055+ * @throws UnsupportedAudioFileException if the <code>File</code> does not point to valid audio
1056+ * file data recognized by the system
1057+ * @throws IOException if an I/O exception occurs
1058+ */
1059+ public static AudioFileFormat getAudioFileFormat(File file)
1060+ throws UnsupportedAudioFileException, IOException {
1061+
1062+ List providers = getAudioFileReaders();
1063+ AudioFileFormat format = null;
1064+
1065+ for(int i = 0; i < providers.size(); i++ ) {
1066+ AudioFileReader reader = (AudioFileReader) providers.get(i);
1067+ try {
1068+ format = reader.getAudioFileFormat( file ); // throws IOException
1069+ break;
1070+ } catch (UnsupportedAudioFileException e) {
1071+ continue;
1072+ }
1073+ }
1074+
1075+ if( format==null ) {
1076+ throw new UnsupportedAudioFileException("file is not a supported file type");
1077+ } else {
1078+ return format;
1079+ }
1080+ }
1081+
1082+
1083+ /**
1084+ * Obtains an audio input stream from the provided input stream. The stream must
1085+ * point to valid audio file data. The implementation of this method may
1086+ * require multiple parsers to
1087+ * examine the stream to determine whether they support it. These parsers must
1088+ * be able to mark the stream, read enough data to determine whether they
1089+ * support the stream, and, if not, reset the stream's read pointer to its original
1090+ * position. If the input stream does not support these operation, this method may fail
1091+ * with an <code>IOException</code>.
1092+ * @param stream the input stream from which the <code>AudioInputStream</code> should be
1093+ * constructed
1094+ * @return an <code>AudioInputStream</code> object based on the audio file data contained
1095+ * in the input stream.
1096+ * @throws UnsupportedAudioFileException if the stream does not point to valid audio
1097+ * file data recognized by the system
1098+ * @throws IOException if an I/O exception occurs
1099+ * @see InputStream#markSupported
1100+ * @see InputStream#mark
1101+ */
1102+ public static AudioInputStream getAudioInputStream(InputStream stream)
1103+ throws UnsupportedAudioFileException, IOException {
1104+
1105+ List providers = getAudioFileReaders();
1106+ AudioInputStream audioStream = null;
1107+
1108+ for(int i = 0; i < providers.size(); i++ ) {
1109+ AudioFileReader reader = (AudioFileReader) providers.get(i);
1110+ try {
1111+ audioStream = reader.getAudioInputStream( stream ); // throws IOException
1112+ break;
1113+ } catch (UnsupportedAudioFileException e) {
1114+ continue;
1115+ }
1116+ }
1117+
1118+ if( audioStream==null ) {
1119+ throw new UnsupportedAudioFileException("could not get audio input stream from input stream");
1120+ } else {
1121+ return audioStream;
1122+ }
1123+ }
1124+
1125+ /**
1126+ * Obtains an audio input stream from the URL provided. The URL must
1127+ * point to valid audio file data.
1128+ * @param url the URL for which the <code>AudioInputStream</code> should be
1129+ * constructed
1130+ * @return an <code>AudioInputStream</code> object based on the audio file data pointed
1131+ * to by the URL
1132+ * @throws UnsupportedAudioFileException if the URL does not point to valid audio
1133+ * file data recognized by the system
1134+ * @throws IOException if an I/O exception occurs
1135+ */
1136+ public static AudioInputStream getAudioInputStream(URL url)
1137+ throws UnsupportedAudioFileException, IOException {
1138+
1139+ List providers = getAudioFileReaders();
1140+ AudioInputStream audioStream = null;
1141+
1142+ for(int i = 0; i < providers.size(); i++ ) {
1143+ AudioFileReader reader = (AudioFileReader) providers.get(i);
1144+ try {
1145+ audioStream = reader.getAudioInputStream( url ); // throws IOException
1146+ break;
1147+ } catch (UnsupportedAudioFileException e) {
1148+ continue;
1149+ }
1150+ }
1151+
1152+ if( audioStream==null ) {
1153+ throw new UnsupportedAudioFileException("could not get audio input stream from input URL");
1154+ } else {
1155+ return audioStream;
1156+ }
1157+ }
1158+
1159+ /**
1160+ * Obtains an audio input stream from the provided <code>File</code>. The <code>File</code> must
1161+ * point to valid audio file data.
1162+ * @param file the <code>File</code> for which the <code>AudioInputStream</code> should be
1163+ * constructed
1164+ * @return an <code>AudioInputStream</code> object based on the audio file data pointed
1165+ * to by the <code>File</code>
1166+ * @throws UnsupportedAudioFileException if the <code>File</code> does not point to valid audio
1167+ * file data recognized by the system
1168+ * @throws IOException if an I/O exception occurs
1169+ */
1170+ public static AudioInputStream getAudioInputStream(File file)
1171+ throws UnsupportedAudioFileException, IOException {
1172+
1173+ List providers = getAudioFileReaders();
1174+ AudioInputStream audioStream = null;
1175+
1176+ for(int i = 0; i < providers.size(); i++ ) {
1177+ AudioFileReader reader = (AudioFileReader) providers.get(i);
1178+ try {
1179+ audioStream = reader.getAudioInputStream( file ); // throws IOException
1180+ break;
1181+ } catch (UnsupportedAudioFileException e) {
1182+ continue;
1183+ }
1184+ }
1185+
1186+ if( audioStream==null ) {
1187+ throw new UnsupportedAudioFileException("could not get audio input stream from input file");
1188+ } else {
1189+ return audioStream;
1190+ }
1191+ }
1192+
1193+
1194+ /**
1195+ * Obtains the file types for which file writing support is provided by the system.
1196+ * @return array of unique file types. If no file types are supported,
1197+ * an array of length 0 is returned.
1198+ */
1199+ public static AudioFileFormat.Type[] getAudioFileTypes() {
1200+ List providers = getAudioFileWriters();
1201+ Set returnTypesSet = new HashSet();
1202+
1203+ for(int i=0; i < providers.size(); i++) {
1204+ AudioFileWriter writer = (AudioFileWriter) providers.get(i);
1205+ AudioFileFormat.Type[] fileTypes = writer.getAudioFileTypes();
1206+ for(int j=0; j < fileTypes.length; j++) {
1207+ returnTypesSet.add(fileTypes[j]);
1208+ }
1209+ }
1210+ AudioFileFormat.Type returnTypes[] = (AudioFileFormat.Type[])
1211+ returnTypesSet.toArray(new AudioFileFormat.Type[0]);
1212+ return returnTypes;
1213+ }
1214+
1215+
1216+ /**
1217+ * Indicates whether file writing support for the specified file type is provided
1218+ * by the system.
1219+ * @param fileType the file type for which write capabilities are queried
1220+ * @return <code>true</code> if the file type is supported,
1221+ * otherwise <code>false</code>
1222+ */
1223+ public static boolean isFileTypeSupported(AudioFileFormat.Type fileType) {
1224+
1225+ List providers = getAudioFileWriters();
1226+
1227+ for(int i=0; i < providers.size(); i++) {
1228+ AudioFileWriter writer = (AudioFileWriter) providers.get(i);
1229+ if (writer.isFileTypeSupported(fileType)) {
1230+ return true;
1231+ }
1232+ }
1233+ return false;
1234+ }
1235+
1236+
1237+ /**
1238+ * Obtains the file types that the system can write from the
1239+ * audio input stream specified.
1240+ * @param stream the audio input stream for which audio file type support
1241+ * is queried
1242+ * @return array of file types. If no file types are supported,
1243+ * an array of length 0 is returned.
1244+ */
1245+ public static AudioFileFormat.Type[] getAudioFileTypes(AudioInputStream stream) {
1246+ List providers = getAudioFileWriters();
1247+ Set returnTypesSet = new HashSet();
1248+
1249+ for(int i=0; i < providers.size(); i++) {
1250+ AudioFileWriter writer = (AudioFileWriter) providers.get(i);
1251+ AudioFileFormat.Type[] fileTypes = writer.getAudioFileTypes(stream);
1252+ for(int j=0; j < fileTypes.length; j++) {
1253+ returnTypesSet.add(fileTypes[j]);
1254+ }
1255+ }
1256+ AudioFileFormat.Type returnTypes[] = (AudioFileFormat.Type[])
1257+ returnTypesSet.toArray(new AudioFileFormat.Type[0]);
1258+ return returnTypes;
1259+ }
1260+
1261+
1262+ /**
1263+ * Indicates whether an audio file of the specified file type can be written
1264+ * from the indicated audio input stream.
1265+ * @param fileType the file type for which write capabilities are queried
1266+ * @param stream the stream for which file-writing support is queried
1267+ * @return <code>true</code> if the file type is supported for this audio input stream,
1268+ * otherwise <code>false</code>
1269+ */
1270+ public static boolean isFileTypeSupported(AudioFileFormat.Type fileType,
1271+ AudioInputStream stream) {
1272+
1273+ List providers = getAudioFileWriters();
1274+
1275+ for(int i=0; i < providers.size(); i++) {
1276+ AudioFileWriter writer = (AudioFileWriter) providers.get(i);
1277+ if(writer.isFileTypeSupported(fileType, stream)) {
1278+ return true;
1279+ }
1280+ }
1281+ return false;
1282+ }
1283+
1284+
1285+ /**
1286+ * Writes a stream of bytes representing an audio file of the specified file type
1287+ * to the output stream provided. Some file types require that
1288+ * the length be written into the file header; such files cannot be written from
1289+ * start to finish unless the length is known in advance. An attempt
1290+ * to write a file of such a type will fail with an IOException if the length in
1291+ * the audio file type is <code>AudioSystem.NOT_SPECIFIED</code>.
1292+ *
1293+ * @param stream the audio input stream containing audio data to be
1294+ * written to the file
1295+ * @param fileType the kind of audio file to write
1296+ * @param out the stream to which the file data should be written
1297+ * @return the number of bytes written to the output stream
1298+ * @throws IOException if an input/output exception occurs
1299+ * @throws IllegalArgumentException if the file type is not supported by
1300+ * the system
1301+ * @see #isFileTypeSupported
1302+ * @see #getAudioFileTypes
1303+ */
1304+ public static int write(AudioInputStream stream, AudioFileFormat.Type fileType,
1305+ OutputStream out) throws IOException {
1306+
1307+ List providers = getAudioFileWriters();
1308+ int bytesWritten = 0;
1309+ boolean flag = false;
1310+
1311+ for(int i=0; i < providers.size(); i++) {
1312+ AudioFileWriter writer = (AudioFileWriter) providers.get(i);
1313+ try {
1314+ bytesWritten = writer.write( stream, fileType, out ); // throws IOException
1315+ flag = true;
1316+ break;
1317+ } catch (IllegalArgumentException e) {
1318+ // thrown if this provider cannot write the sequence, try the next
1319+ continue;
1320+ }
1321+ }
1322+ if(!flag) {
1323+ throw new IllegalArgumentException("could not write audio file: file type not supported: " + fileType);
1324+ } else {
1325+ return bytesWritten;
1326+ }
1327+ }
1328+
1329+
1330+ /**
1331+ * Writes a stream of bytes representing an audio file of the specified file type
1332+ * to the external file provided.
1333+ * @param stream the audio input stream containing audio data to be
1334+ * written to the file
1335+ * @param fileType the kind of audio file to write
1336+ * @param out the external file to which the file data should be written
1337+ * @return the number of bytes written to the file
1338+ * @throws IOException if an I/O exception occurs
1339+ * @throws IllegalArgumentException if the file type is not supported by
1340+ * the system
1341+ * @see #isFileTypeSupported
1342+ * @see #getAudioFileTypes
1343+ */
1344+ public static int write(AudioInputStream stream, AudioFileFormat.Type fileType,
1345+ File out) throws IOException {
1346+
1347+ List providers = getAudioFileWriters();
1348+ int bytesWritten = 0;
1349+ boolean flag = false;
1350+
1351+ for(int i=0; i < providers.size(); i++) {
1352+ AudioFileWriter writer = (AudioFileWriter) providers.get(i);
1353+ try {
1354+ bytesWritten = writer.write( stream, fileType, out ); // throws IOException
1355+ flag = true;
1356+ break;
1357+ } catch (IllegalArgumentException e) {
1358+ // thrown if this provider cannot write the sequence, try the next
1359+ continue;
1360+ }
1361+ }
1362+ if (!flag) {
1363+ throw new IllegalArgumentException("could not write audio file: file type not supported: " + fileType);
1364+ } else {
1365+ return bytesWritten;
1366+ }
1367+ }
1368+
1369+
1370+ // METHODS FOR INTERNAL IMPLEMENTATION USE
1371+
1372+ /**
1373+ * Obtains the set of MixerProviders on the system.
1374+ */
1375+ private static List getMixerProviders() {
1376+ return getProviders(MixerProvider.class);
1377+ }
1378+
1379+
1380+ /**
1381+ * Obtains the set of format converters (codecs, transcoders, etc.)
1382+ * that are currently installed on the system.
1383+ * @return an array of
1384+ * {@link javax.sound.sampled.spi.FormatConversionProvider
1385+ * FormatConversionProvider}
1386+ * objects representing the available format converters. If no format
1387+ * converters readers are available on the system, an array of length 0 is
1388+ * returned.
1389+ */
1390+ private static List getFormatConversionProviders() {
1391+ return getProviders(FormatConversionProvider.class);
1392+ }
1393+
1394+
1395+ /**
1396+ * Obtains the set of audio file readers that are currently installed on the system.
1397+ * @return a List of
1398+ * {@link javax.sound.sampled.spi.AudioFileReader
1399+ * AudioFileReader}
1400+ * objects representing the installed audio file readers. If no audio file
1401+ * readers are available on the system, an empty List is returned.
1402+ */
1403+ private static List getAudioFileReaders() {
1404+ return getProviders(AudioFileReader.class);
1405+ }
1406+
1407+
1408+ /**
1409+ * Obtains the set of audio file writers that are currently installed on the system.
1410+ * @return a List of
1411+ * {@link javax.sound.samples.spi.AudioFileWriter AudioFileWriter}
1412+ * objects representing the available audio file writers. If no audio file
1413+ * writers are available on the system, an empty List is returned.
1414+ */
1415+ private static List getAudioFileWriters() {
1416+ return getProviders(AudioFileWriter.class);
1417+ }
1418+
1419+
1420+
1421+ /** Attempts to locate and return a default Mixer that provides lines
1422+ * of the specified type.
1423+ *
1424+ * @param providers the installed mixer providers
1425+ * @param info The requested line type
1426+ * TargetDataLine.class, Clip.class or Port.class.
1427+ * @return a Mixer that matches the requirements, or null if no default mixer found
1428+ */
1429+ private static Mixer getDefaultMixer(List providers, Line.Info info) {
1430+ Class lineClass = info.getLineClass();
1431+ String providerClassName = JDK13Services.getDefaultProviderClassName(lineClass);
1432+ String instanceName = JDK13Services.getDefaultInstanceName(lineClass);
1433+ Mixer mixer;
1434+
1435+ if (providerClassName != null) {
1436+ MixerProvider defaultProvider = getNamedProvider(providerClassName, providers);
1437+ if (defaultProvider != null) {
1438+ if (instanceName != null) {
1439+ mixer = getNamedMixer(instanceName, defaultProvider, info);
1440+ if (mixer != null) {
1441+ return mixer;
1442+ }
1443+ } else {
1444+ mixer = getFirstMixer(defaultProvider, info,
1445+ false /* mixing not required*/);
1446+ if (mixer != null) {
1447+ return mixer;
1448+ }
1449+ }
1450+
1451+ }
1452+ }
1453+
1454+ /* Provider class not specified or
1455+ provider class cannot be found, or
1456+ provider class and instance specified and instance cannot be found or is not appropriate */
1457+ if (instanceName != null) {
1458+ mixer = getNamedMixer(instanceName, providers, info);
1459+ if (mixer != null) {
1460+ return mixer;
1461+ }
1462+ }
1463+
1464+
1465+ /* No default are specified, or if something is specified, everything
1466+ failed. */
1467+ return null;
1468+ }
1469+
1470+
1471+
1472+ /** Return a MixerProvider of a given class from the list of
1473+ MixerProviders.
1474+
1475+ This method never requires the returned Mixer to do mixing.
1476+ @param providerClassName The class name of the provider to be returned.
1477+ @param providers The list of MixerProviders that is searched.
1478+ @return A MixerProvider of the requested class, or null if none is
1479+ found.
1480+ */
1481+ private static MixerProvider getNamedProvider(String providerClassName,
1482+ List providers) {
1483+ for(int i = 0; i < providers.size(); i++) {
1484+ MixerProvider provider = (MixerProvider) providers.get(i);
1485+ if (provider.getClass().getName().equals(providerClassName)) {
1486+ return provider;
1487+ }
1488+ }
1489+ return null;
1490+ }
1491+
1492+
1493+ /** Return a Mixer with a given name from a given MixerProvider.
1494+ This method never requires the returned Mixer to do mixing.
1495+ @param mixerName The name of the Mixer to be returned.
1496+ @param provider The MixerProvider to check for Mixers.
1497+ @param info The type of line the returned Mixer is required to
1498+ support.
1499+
1500+ @return A Mixer matching the requirements, or null if none is found.
1501+ */
1502+ private static Mixer getNamedMixer(String mixerName,
1503+ MixerProvider provider,
1504+ Line.Info info) {
1505+ Mixer.Info[] infos = provider.getMixerInfo();
1506+ for (int i = 0; i < infos.length; i++) {
1507+ if (infos[i].getName().equals(mixerName)) {
1508+ Mixer mixer = provider.getMixer(infos[i]);
1509+ if (isAppropriateMixer(mixer, info, false)) {
1510+ return mixer;
1511+ }
1512+ }
1513+ }
1514+ return null;
1515+ }
1516+
1517+
1518+ /** From a List of MixerProviders, return a Mixer with a given name.
1519+ This method never requires the returned Mixer to do mixing.
1520+ @param mixerName The name of the Mixer to be returned.
1521+ @param providers The List of MixerProviders to check for Mixers.
1522+ @param info The type of line the returned Mixer is required to
1523+ support.
1524+ @return A Mixer matching the requirements, or null if none is found.
1525+ */
1526+ private static Mixer getNamedMixer(String mixerName,
1527+ List providers,
1528+ Line.Info info) {
1529+ for(int i = 0; i < providers.size(); i++) {
1530+ MixerProvider provider = (MixerProvider) providers.get(i);
1531+ Mixer mixer = getNamedMixer(mixerName, provider, info);
1532+ if (mixer != null) {
1533+ return mixer;
1534+ }
1535+ }
1536+ return null;
1537+ }
1538+
1539+
1540+ /** From a given MixerProvider, return the first appropriate Mixer.
1541+ @param provider The MixerProvider to check for Mixers.
1542+ @param info The type of line the returned Mixer is required to
1543+ support.
1544+ @param isMixingRequired If true, only Mixers that support mixing are
1545+ returned for line types of SourceDataLine and Clip.
1546+
1547+ @return A Mixer that is considered appropriate, or null
1548+ if none is found.
1549+ */
1550+ private static Mixer getFirstMixer(MixerProvider provider,
1551+ Line.Info info,
1552+ 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+
1564+ /** Checks if a Mixer is appropriate.
1565+ A Mixer is considered appropriate if it support the given line type.
1566+ If isMixingRequired is true and the line type is an output one
1567+ (SourceDataLine, Clip), the mixer is appropriate if it supports
1568+ at least 2 (concurrent) lines of the given type.
1569+
1570+ @return true if the mixer is considered appropriate according to the
1571+ rules given above, false otherwise.
1572+ */
1573+ private static boolean isAppropriateMixer(Mixer mixer,
1574+ Line.Info lineInfo,
1575+ boolean isMixingRequired) {
1576+ if (! mixer.isLineSupported(lineInfo)) {
1577+ return false;
1578+ }
1579+ Class lineClass = lineInfo.getLineClass();
1580+ if (isMixingRequired
1581+ && (SourceDataLine.class.isAssignableFrom(lineClass) ||
1582+ Clip.class.isAssignableFrom(lineClass))) {
1583+ int maxLines = mixer.getMaxLines(lineInfo);
1584+ return ((maxLines == NOT_SPECIFIED) || (maxLines > 1));
1585+ }
1586+ return true;
1587+ }
1588+
1589+
1590+
1591+ /**
1592+ * Like getMixerInfo, but return List
1593+ */
1594+ private static List getMixerInfoList() {
1595+ List providers = getMixerProviders();
1596+ return getMixerInfoList(providers);
1597+ }
1598+
1599+
1600+ /**
1601+ * Like getMixerInfo, but return List
1602+ */
1603+ private static List getMixerInfoList(List providers) {
1604+ List infos = new ArrayList();
1605+
1606+ Mixer.Info[] someInfos; // per-mixer
1607+ Mixer.Info[] allInfos; // for all mixers
1608+
1609+ for(int i = 0; i < providers.size(); i++ ) {
1610+ someInfos = (Mixer.Info[])
1611+ ((MixerProvider)providers.get(i)).getMixerInfo();
1612+
1613+ for (int j = 0; j < someInfos.length; j++) {
1614+ infos.add(someInfos[j]);
1615+ }
1616+ }
1617+
1618+ return infos;
1619+ }
1620+
1621+
1622+ /**
1623+ * Obtains the set of services currently installed on the system
1624+ * using sun.misc.Service, the SPI mechanism in 1.3.
1625+ * @return a List of instances of providers for the requested service.
1626+ * If no providers are available, a vector of length 0 will be returned.
1627+ */
1628+ private static List getProviders(Class providerClass) {
1629+ return JDK13Services.getProviders(providerClass);
1630+ }
1631+}