Path: blob/aarch64-shenandoah-jdk8u272-b10/jdk/src/share/classes/javax/sound/sampled/AudioSystem.java
38918 views
/*1* Copyright (c) 1999, 2013, Oracle and/or its affiliates. All rights reserved.2* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.3*4* This code is free software; you can redistribute it and/or modify it5* under the terms of the GNU General Public License version 2 only, as6* published by the Free Software Foundation. Oracle designates this7* particular file as subject to the "Classpath" exception as provided8* by Oracle in the LICENSE file that accompanied this code.9*10* This code is distributed in the hope that it will be useful, but WITHOUT11* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or12* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License13* version 2 for more details (a copy is included in the LICENSE file that14* accompanied this code).15*16* You should have received a copy of the GNU General Public License version17* 2 along with this work; if not, write to the Free Software Foundation,18* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.19*20* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA21* or visit www.oracle.com if you need additional information or have any22* questions.23*/2425package javax.sound.sampled;2627import java.io.File;28import java.io.InputStream;29import java.io.IOException;30import java.io.OutputStream;31import java.net.URL;3233import java.util.HashSet;34import java.util.List;35import java.util.Set;36import java.util.Vector;37import java.util.ArrayList;3839import javax.sound.sampled.spi.AudioFileWriter;40import javax.sound.sampled.spi.AudioFileReader;41import javax.sound.sampled.spi.FormatConversionProvider;42import javax.sound.sampled.spi.MixerProvider;4344import com.sun.media.sound.JDK13Services;4546/* $fb TODO:47* - consistent usage of (typed) collections48*/495051/**52* The <code>AudioSystem</code> class acts as the entry point to the53* sampled-audio system resources. This class lets you query and54* access the mixers that are installed on the system.55* <code>AudioSystem</code> includes a number of56* methods for converting audio data between different formats, and for57* translating between audio files and streams. It also provides a method58* for obtaining a <code>{@link Line}</code> directly from the59* <code>AudioSystem</code> without dealing explicitly60* with mixers.61*62* <p>Properties can be used to specify the default mixer63* for specific line types.64* Both system properties and a properties file are considered.65* The <code>sound.properties</code> properties file is read from66* an implementation-specific location (typically it is the <code>lib</code>67* directory in the Java installation directory).68* If a property exists both as a system property and in the69* properties file, the system property takes precedence. If none is70* specified, a suitable default is chosen among the available devices.71* The syntax of the properties file is specified in72* {@link java.util.Properties#load(InputStream) Properties.load}. The73* following table lists the available property keys and which methods74* consider them:75*76* <table border=0>77* <caption>Audio System Property Keys</caption>78* <tr>79* <th>Property Key</th>80* <th>Interface</th>81* <th>Affected Method(s)</th>82* </tr>83* <tr>84* <td><code>javax.sound.sampled.Clip</code></td>85* <td>{@link Clip}</td>86* <td>{@link #getLine}, {@link #getClip}</td>87* </tr>88* <tr>89* <td><code>javax.sound.sampled.Port</code></td>90* <td>{@link Port}</td>91* <td>{@link #getLine}</td>92* </tr>93* <tr>94* <td><code>javax.sound.sampled.SourceDataLine</code></td>95* <td>{@link SourceDataLine}</td>96* <td>{@link #getLine}, {@link #getSourceDataLine}</td>97* </tr>98* <tr>99* <td><code>javax.sound.sampled.TargetDataLine</code></td>100* <td>{@link TargetDataLine}</td>101* <td>{@link #getLine}, {@link #getTargetDataLine}</td>102* </tr>103* </table>104*105* The property value consists of the provider class name106* and the mixer name, separated by the hash mark ("#").107* The provider class name is the fully-qualified108* name of a concrete {@link javax.sound.sampled.spi.MixerProvider109* mixer provider} class. The mixer name is matched against110* the <code>String</code> returned by the <code>getName</code>111* method of <code>Mixer.Info</code>.112* Either the class name, or the mixer name may be omitted.113* If only the class name is specified, the trailing hash mark114* is optional.115*116* <p>If the provider class is specified, and it can be117* successfully retrieved from the installed providers, the list of118* <code>Mixer.Info</code> objects is retrieved119* from the provider. Otherwise, or when these mixers120* do not provide a subsequent match, the list is retrieved121* from {@link #getMixerInfo} to contain122* all available <code>Mixer.Info</code> objects.123*124* <p>If a mixer name is specified, the resulting list of125* <code>Mixer.Info</code> objects is searched:126* the first one with a matching name, and whose127* <code>Mixer</code> provides the128* respective line interface, will be returned.129* If no matching <code>Mixer.Info</code> object130* is found, or the mixer name is not specified,131* the first mixer from the resulting132* list, which provides the respective line133* interface, will be returned.134*135* For example, the property <code>javax.sound.sampled.Clip</code>136* with a value137* <code>"com.sun.media.sound.MixerProvider#SunClip"</code>138* will have the following consequences when139* <code>getLine</code> is called requesting a <code>Clip</code>140* instance:141* if the class <code>com.sun.media.sound.MixerProvider</code> exists142* in the list of installed mixer providers,143* the first <code>Clip</code> from the first mixer with name144* <code>"SunClip"</code> will be returned. If it cannot145* be found, the first <code>Clip</code> from the first mixer146* of the specified provider will be returned, regardless of name.147* If there is none, the first <code>Clip</code> from the first148* <code>Mixer</code> with name149* <code>"SunClip"</code> in the list of all mixers150* (as returned by <code>getMixerInfo</code>) will be returned,151* or, if not found, the first <code>Clip</code> of the first152* <code>Mixer</code>that can be found in the list of all153* mixers is returned.154* If that fails, too, an <code>IllegalArgumentException</code>155* is thrown.156*157* @author Kara Kytle158* @author Florian Bomers159* @author Matthias Pfisterer160* @author Kevin P. Smith161*162* @see AudioFormat163* @see AudioInputStream164* @see Mixer165* @see Line166* @see Line.Info167* @since 1.3168*/169public class AudioSystem {170171/**172* An integer that stands for an unknown numeric value.173* This value is appropriate only for signed quantities that do not174* normally take negative values. Examples include file sizes, frame175* sizes, buffer sizes, and sample rates.176* A number of Java Sound constructors accept177* a value of <code>NOT_SPECIFIED</code> for such parameters. Other178* methods may also accept or return this value, as documented.179*/180public static final int NOT_SPECIFIED = -1;181182/**183* Private no-args constructor for ensuring against instantiation.184*/185private AudioSystem() {186}187188189/**190* Obtains an array of mixer info objects that represents191* the set of audio mixers that are currently installed on the system.192* @return an array of info objects for the currently installed mixers. If no mixers193* are available on the system, an array of length 0 is returned.194* @see #getMixer195*/196public static Mixer.Info[] getMixerInfo() {197198List infos = getMixerInfoList();199Mixer.Info[] allInfos = (Mixer.Info[]) infos.toArray(new Mixer.Info[infos.size()]);200return allInfos;201}202203204/**205* Obtains the requested audio mixer.206* @param info a <code>Mixer.Info</code> object representing the desired207* mixer, or <code>null</code> for the system default mixer208* @return the requested mixer209* @throws SecurityException if the requested mixer210* is unavailable because of security restrictions211* @throws IllegalArgumentException if the info object does not represent212* a mixer installed on the system213* @see #getMixerInfo214*/215public static Mixer getMixer(Mixer.Info info) {216217Mixer mixer = null;218List providers = getMixerProviders();219220for(int i = 0; i < providers.size(); i++ ) {221222try {223return ((MixerProvider)providers.get(i)).getMixer(info);224225} catch (IllegalArgumentException e) {226} catch (NullPointerException e) {227// $$jb 08.20.99: If the strings in the info object aren't228// set, then Netscape (using jdk1.1.5) tends to throw229// NPE's when doing some string manipulation. This is230// probably not the best fix, but is solves the problem231// of the NPE in Netscape using local classes232// $$jb 11.01.99: Replacing this patch.233}234}235236//$$fb if looking for default mixer, and not found yet, add a round of looking237if (info == null) {238for(int i = 0; i < providers.size(); i++ ) {239try {240MixerProvider provider = (MixerProvider) providers.get(i);241Mixer.Info[] infos = provider.getMixerInfo();242// start from 0 to last device (do not reverse this order)243for (int ii = 0; ii < infos.length; ii++) {244try {245return provider.getMixer(infos[ii]);246} catch (IllegalArgumentException e) {247// this is not a good default device :)248}249}250} catch (IllegalArgumentException e) {251} catch (NullPointerException e) {252}253}254}255256257throw new IllegalArgumentException("Mixer not supported: "258+ (info!=null?info.toString():"null"));259}260261262//$$fb 2002-11-26: fix for 4757930: DOC: AudioSystem.getTarget/SourceLineInfo() is ambiguous263/**264* Obtains information about all source lines of a particular type that are supported265* by the installed mixers.266* @param info a <code>Line.Info</code> object that specifies the kind of267* lines about which information is requested268* @return an array of <code>Line.Info</code> objects describing source lines matching269* the type requested. If no matching source lines are supported, an array of length 0270* is returned.271*272* @see Mixer#getSourceLineInfo(Line.Info)273*/274public static Line.Info[] getSourceLineInfo(Line.Info info) {275276Vector vector = new Vector();277Line.Info[] currentInfoArray;278279Mixer mixer;280Line.Info fullInfo = null;281Mixer.Info[] infoArray = getMixerInfo();282283for (int i = 0; i < infoArray.length; i++) {284285mixer = getMixer(infoArray[i]);286287currentInfoArray = mixer.getSourceLineInfo(info);288for (int j = 0; j < currentInfoArray.length; j++) {289vector.addElement(currentInfoArray[j]);290}291}292293Line.Info[] returnedArray = new Line.Info[vector.size()];294295for (int i = 0; i < returnedArray.length; i++) {296returnedArray[i] = (Line.Info)vector.get(i);297}298299return returnedArray;300}301302303/**304* Obtains information about all target lines of a particular type that are supported305* by the installed mixers.306* @param info a <code>Line.Info</code> object that specifies the kind of307* lines about which information is requested308* @return an array of <code>Line.Info</code> objects describing target lines matching309* the type requested. If no matching target lines are supported, an array of length 0310* is returned.311*312* @see Mixer#getTargetLineInfo(Line.Info)313*/314public static Line.Info[] getTargetLineInfo(Line.Info info) {315316Vector vector = new Vector();317Line.Info[] currentInfoArray;318319Mixer mixer;320Line.Info fullInfo = null;321Mixer.Info[] infoArray = getMixerInfo();322323for (int i = 0; i < infoArray.length; i++) {324325mixer = getMixer(infoArray[i]);326327currentInfoArray = mixer.getTargetLineInfo(info);328for (int j = 0; j < currentInfoArray.length; j++) {329vector.addElement(currentInfoArray[j]);330}331}332333Line.Info[] returnedArray = new Line.Info[vector.size()];334335for (int i = 0; i < returnedArray.length; i++) {336returnedArray[i] = (Line.Info)vector.get(i);337}338339return returnedArray;340}341342343/**344* Indicates whether the system supports any lines that match345* the specified <code>Line.Info</code> object. A line is supported if346* any installed mixer supports it.347* @param info a <code>Line.Info</code> object describing the line for which support is queried348* @return <code>true</code> if at least one matching line is349* supported, otherwise <code>false</code>350*351* @see Mixer#isLineSupported(Line.Info)352*/353public static boolean isLineSupported(Line.Info info) {354355Mixer mixer;356Mixer.Info[] infoArray = getMixerInfo();357358for (int i = 0; i < infoArray.length; i++) {359360if( infoArray[i] != null ) {361mixer = getMixer(infoArray[i]);362if (mixer.isLineSupported(info)) {363return true;364}365}366}367368return false;369}370371/**372* Obtains a line that matches the description in the specified373* <code>Line.Info</code> object.374*375* <p>If a <code>DataLine</code> is requested, and <code>info</code>376* is an instance of <code>DataLine.Info</code> specifying at least377* one fully qualified audio format, the last one378* will be used as the default format of the returned379* <code>DataLine</code>.380*381* <p>If system properties382* <code>javax.sound.sampled.Clip</code>,383* <code>javax.sound.sampled.Port</code>,384* <code>javax.sound.sampled.SourceDataLine</code> and385* <code>javax.sound.sampled.TargetDataLine</code> are defined386* or they are defined in the file "sound.properties",387* they are used to retrieve default lines.388* For details, refer to the {@link AudioSystem class description}.389*390* If the respective property is not set, or the mixer391* requested in the property is not installed or does not provide the392* requested line, all installed mixers are queried for the393* requested line type. A Line will be returned from the first mixer394* providing the requested line type.395*396* @param info a <code>Line.Info</code> object describing the desired kind of line397* @return a line of the requested kind398*399* @throws LineUnavailableException if a matching line400* is not available due to resource restrictions401* @throws SecurityException if a matching line402* is not available due to security restrictions403* @throws IllegalArgumentException if the system does not404* support at least one line matching the specified405* <code>Line.Info</code> object406* through any installed mixer407*/408public static Line getLine(Line.Info info) throws LineUnavailableException {409LineUnavailableException lue = null;410List providers = getMixerProviders();411412413// 1: try from default mixer for this line class414try {415Mixer mixer = getDefaultMixer(providers, info);416if (mixer != null && mixer.isLineSupported(info)) {417return mixer.getLine(info);418}419} catch (LineUnavailableException e) {420lue = e;421} catch (IllegalArgumentException iae) {422// must not happen... but better to catch it here,423// if plug-ins are badly written424}425426427// 2: if that doesn't work, try to find any mixing mixer428for(int i = 0; i < providers.size(); i++) {429MixerProvider provider = (MixerProvider) providers.get(i);430Mixer.Info[] infos = provider.getMixerInfo();431432for (int j = 0; j < infos.length; j++) {433try {434Mixer mixer = provider.getMixer(infos[j]);435// see if this is an appropriate mixer which can mix436if (isAppropriateMixer(mixer, info, true)) {437return mixer.getLine(info);438}439} catch (LineUnavailableException e) {440lue = e;441} catch (IllegalArgumentException iae) {442// must not happen... but better to catch it here,443// if plug-ins are badly written444}445}446}447448449// 3: if that didn't work, try to find any non-mixing mixer450for(int i = 0; i < providers.size(); i++) {451MixerProvider provider = (MixerProvider) providers.get(i);452Mixer.Info[] infos = provider.getMixerInfo();453for (int j = 0; j < infos.length; j++) {454try {455Mixer mixer = provider.getMixer(infos[j]);456// see if this is an appropriate mixer which can mix457if (isAppropriateMixer(mixer, info, false)) {458return mixer.getLine(info);459}460} catch (LineUnavailableException e) {461lue = e;462} catch (IllegalArgumentException iae) {463// must not happen... but better to catch it here,464// if plug-ins are badly written465}466}467}468469// if this line was supported but was not available, throw the last470// LineUnavailableException we got (??).471if (lue != null) {472throw lue;473}474475// otherwise, the requested line was not supported, so throw476// an Illegal argument exception477throw new IllegalArgumentException("No line matching " +478info.toString() + " is supported.");479}480481482/**483* Obtains a clip that can be used for playing back484* an audio file or an audio stream. The returned clip485* will be provided by the default system mixer, or,486* if not possible, by any other mixer installed in the487* system that supports a <code>Clip</code>488* object.489*490* <p>The returned clip must be opened with the491* <code>open(AudioFormat)</code> or492* <code>open(AudioInputStream)</code> method.493*494* <p>This is a high-level method that uses <code>getMixer</code>495* and <code>getLine</code> internally.496*497* <p>If the system property498* <code>javax.sound.sampled.Clip</code>499* is defined or it is defined in the file "sound.properties",500* it is used to retrieve the default clip.501* For details, refer to the {@link AudioSystem class description}.502*503* @return the desired clip object504*505* @throws LineUnavailableException if a clip object506* is not available due to resource restrictions507* @throws SecurityException if a clip object508* is not available due to security restrictions509* @throws IllegalArgumentException if the system does not510* support at least one clip instance through any installed mixer511*512* @see #getClip(Mixer.Info)513* @since 1.5514*/515public static Clip getClip() throws LineUnavailableException{516AudioFormat format = new AudioFormat(AudioFormat.Encoding.PCM_SIGNED,517AudioSystem.NOT_SPECIFIED,51816, 2, 4,519AudioSystem.NOT_SPECIFIED, true);520DataLine.Info info = new DataLine.Info(Clip.class, format);521return (Clip) AudioSystem.getLine(info);522}523524525/**526* Obtains a clip from the specified mixer that can be527* used for playing back an audio file or an audio stream.528*529* <p>The returned clip must be opened with the530* <code>open(AudioFormat)</code> or531* <code>open(AudioInputStream)</code> method.532*533* <p>This is a high-level method that uses <code>getMixer</code>534* and <code>getLine</code> internally.535*536* @param mixerInfo a <code>Mixer.Info</code> object representing the537* desired mixer, or <code>null</code> for the system default mixer538* @return a clip object from the specified mixer539*540* @throws LineUnavailableException if a clip541* is not available from this mixer due to resource restrictions542* @throws SecurityException if a clip543* is not available from this mixer due to security restrictions544* @throws IllegalArgumentException if the system does not545* support at least one clip through the specified mixer546*547* @see #getClip()548* @since 1.5549*/550public static Clip getClip(Mixer.Info mixerInfo) throws LineUnavailableException{551AudioFormat format = new AudioFormat(AudioFormat.Encoding.PCM_SIGNED,552AudioSystem.NOT_SPECIFIED,55316, 2, 4,554AudioSystem.NOT_SPECIFIED, true);555DataLine.Info info = new DataLine.Info(Clip.class, format);556Mixer mixer = AudioSystem.getMixer(mixerInfo);557return (Clip) mixer.getLine(info);558}559560561/**562* Obtains a source data line that can be used for playing back563* audio data in the format specified by the564* <code>AudioFormat</code> object. The returned line565* will be provided by the default system mixer, or,566* if not possible, by any other mixer installed in the567* system that supports a matching568* <code>SourceDataLine</code> object.569*570* <p>The returned line should be opened with the571* <code>open(AudioFormat)</code> or572* <code>open(AudioFormat, int)</code> method.573*574* <p>This is a high-level method that uses <code>getMixer</code>575* and <code>getLine</code> internally.576*577* <p>The returned <code>SourceDataLine</code>'s default578* audio format will be initialized with <code>format</code>.579*580* <p>If the system property581* <code>javax.sound.sampled.SourceDataLine</code>582* is defined or it is defined in the file "sound.properties",583* it is used to retrieve the default source data line.584* For details, refer to the {@link AudioSystem class description}.585*586* @param format an <code>AudioFormat</code> object specifying587* the supported audio format of the returned line,588* or <code>null</code> for any audio format589* @return the desired <code>SourceDataLine</code> object590*591* @throws LineUnavailableException if a matching source data line592* is not available due to resource restrictions593* @throws SecurityException if a matching source data line594* is not available due to security restrictions595* @throws IllegalArgumentException if the system does not596* support at least one source data line supporting the597* specified audio format through any installed mixer598*599* @see #getSourceDataLine(AudioFormat, Mixer.Info)600* @since 1.5601*/602public static SourceDataLine getSourceDataLine(AudioFormat format)603throws LineUnavailableException{604DataLine.Info info = new DataLine.Info(SourceDataLine.class, format);605return (SourceDataLine) AudioSystem.getLine(info);606}607608609/**610* Obtains a source data line that can be used for playing back611* audio data in the format specified by the612* <code>AudioFormat</code> object, provided by the mixer613* specified by the <code>Mixer.Info</code> object.614*615* <p>The returned line should be opened with the616* <code>open(AudioFormat)</code> or617* <code>open(AudioFormat, int)</code> method.618*619* <p>This is a high-level method that uses <code>getMixer</code>620* and <code>getLine</code> internally.621*622* <p>The returned <code>SourceDataLine</code>'s default623* audio format will be initialized with <code>format</code>.624*625* @param format an <code>AudioFormat</code> object specifying626* the supported audio format of the returned line,627* or <code>null</code> for any audio format628* @param mixerinfo a <code>Mixer.Info</code> object representing629* the desired mixer, or <code>null</code> for the system630* default mixer631* @return the desired <code>SourceDataLine</code> object632*633* @throws LineUnavailableException if a matching source data634* line is not available from the specified mixer due635* to resource restrictions636* @throws SecurityException if a matching source data line637* is not available from the specified mixer due to638* security restrictions639* @throws IllegalArgumentException if the specified mixer does640* not support at least one source data line supporting641* the specified audio format642*643* @see #getSourceDataLine(AudioFormat)644* @since 1.5645*/646public static SourceDataLine getSourceDataLine(AudioFormat format,647Mixer.Info mixerinfo)648throws LineUnavailableException{649DataLine.Info info = new DataLine.Info(SourceDataLine.class, format);650Mixer mixer = AudioSystem.getMixer(mixerinfo);651return (SourceDataLine) mixer.getLine(info);652}653654655/**656* Obtains a target data line that can be used for recording657* audio data in the format specified by the658* <code>AudioFormat</code> object. The returned line659* will be provided by the default system mixer, or,660* if not possible, by any other mixer installed in the661* system that supports a matching662* <code>TargetDataLine</code> object.663*664* <p>The returned line should be opened with the665* <code>open(AudioFormat)</code> or666* <code>open(AudioFormat, int)</code> method.667*668* <p>This is a high-level method that uses <code>getMixer</code>669* and <code>getLine</code> internally.670*671* <p>The returned <code>TargetDataLine</code>'s default672* audio format will be initialized with <code>format</code>.673*674* <p>If the system property675* {@code javax.sound.sampled.TargetDataLine}676* is defined or it is defined in the file "sound.properties",677* it is used to retrieve the default target data line.678* For details, refer to the {@link AudioSystem class description}.679*680* @param format an <code>AudioFormat</code> object specifying681* the supported audio format of the returned line,682* or <code>null</code> for any audio format683* @return the desired <code>TargetDataLine</code> object684*685* @throws LineUnavailableException if a matching target data line686* is not available due to resource restrictions687* @throws SecurityException if a matching target data line688* is not available due to security restrictions689* @throws IllegalArgumentException if the system does not690* support at least one target data line supporting the691* specified audio format through any installed mixer692*693* @see #getTargetDataLine(AudioFormat, Mixer.Info)694* @see AudioPermission695* @since 1.5696*/697public static TargetDataLine getTargetDataLine(AudioFormat format)698throws LineUnavailableException{699700DataLine.Info info = new DataLine.Info(TargetDataLine.class, format);701return (TargetDataLine) AudioSystem.getLine(info);702}703704705706/**707* Obtains a target data line that can be used for recording708* audio data in the format specified by the709* <code>AudioFormat</code> object, provided by the mixer710* specified by the <code>Mixer.Info</code> object.711*712* <p>The returned line should be opened with the713* <code>open(AudioFormat)</code> or714* <code>open(AudioFormat, int)</code> method.715*716* <p>This is a high-level method that uses <code>getMixer</code>717* and <code>getLine</code> internally.718*719* <p>The returned <code>TargetDataLine</code>'s default720* audio format will be initialized with <code>format</code>.721*722* @param format an <code>AudioFormat</code> object specifying723* the supported audio format of the returned line,724* or <code>null</code> for any audio format725* @param mixerinfo a <code>Mixer.Info</code> object representing the726* desired mixer, or <code>null</code> for the system default mixer727* @return the desired <code>TargetDataLine</code> object728*729* @throws LineUnavailableException if a matching target data730* line is not available from the specified mixer due731* to resource restrictions732* @throws SecurityException if a matching target data line733* is not available from the specified mixer due to734* security restrictions735* @throws IllegalArgumentException if the specified mixer does736* not support at least one target data line supporting737* the specified audio format738*739* @see #getTargetDataLine(AudioFormat)740* @see AudioPermission741* @since 1.5742*/743public static TargetDataLine getTargetDataLine(AudioFormat format,744Mixer.Info mixerinfo)745throws LineUnavailableException {746747DataLine.Info info = new DataLine.Info(TargetDataLine.class, format);748Mixer mixer = AudioSystem.getMixer(mixerinfo);749return (TargetDataLine) mixer.getLine(info);750}751752753// $$fb 2002-04-12: fix for 4662082: behavior of AudioSystem.getTargetEncodings() methods doesn't match the spec754/**755* Obtains the encodings that the system can obtain from an756* audio input stream with the specified encoding using the set757* of installed format converters.758* @param sourceEncoding the encoding for which conversion support759* is queried760* @return array of encodings. If <code>sourceEncoding</code>is not supported,761* an array of length 0 is returned. Otherwise, the array will have a length762* of at least 1, representing <code>sourceEncoding</code> (no conversion).763*/764public static AudioFormat.Encoding[] getTargetEncodings(AudioFormat.Encoding sourceEncoding) {765766List codecs = getFormatConversionProviders();767Vector encodings = new Vector();768769AudioFormat.Encoding encs[] = null;770771// gather from all the codecs772for(int i=0; i<codecs.size(); i++ ) {773FormatConversionProvider codec = (FormatConversionProvider) codecs.get(i);774if( codec.isSourceEncodingSupported( sourceEncoding ) ) {775encs = codec.getTargetEncodings();776for (int j = 0; j < encs.length; j++) {777encodings.addElement( encs[j] );778}779}780}781AudioFormat.Encoding encs2[] = (AudioFormat.Encoding[]) encodings.toArray(new AudioFormat.Encoding[0]);782return encs2;783}784785786787// $$fb 2002-04-12: fix for 4662082: behavior of AudioSystem.getTargetEncodings() methods doesn't match the spec788/**789* Obtains the encodings that the system can obtain from an790* audio input stream with the specified format using the set791* of installed format converters.792* @param sourceFormat the audio format for which conversion793* is queried794* @return array of encodings. If <code>sourceFormat</code>is not supported,795* an array of length 0 is returned. Otherwise, the array will have a length796* of at least 1, representing the encoding of <code>sourceFormat</code> (no conversion).797*/798public static AudioFormat.Encoding[] getTargetEncodings(AudioFormat sourceFormat) {799800801List codecs = getFormatConversionProviders();802Vector encodings = new Vector();803804int size = 0;805int index = 0;806AudioFormat.Encoding encs[] = null;807808// gather from all the codecs809810for(int i=0; i<codecs.size(); i++ ) {811encs = ((FormatConversionProvider) codecs.get(i)).getTargetEncodings(sourceFormat);812size += encs.length;813encodings.addElement( encs );814}815816// now build a new array817818AudioFormat.Encoding encs2[] = new AudioFormat.Encoding[size];819for(int i=0; i<encodings.size(); i++ ) {820encs = (AudioFormat.Encoding [])(encodings.get(i));821for(int j=0; j<encs.length; j++ ) {822encs2[index++] = encs[j];823}824}825return encs2;826}827828829/**830* Indicates whether an audio input stream of the specified encoding831* can be obtained from an audio input stream that has the specified832* format.833* @param targetEncoding the desired encoding after conversion834* @param sourceFormat the audio format before conversion835* @return <code>true</code> if the conversion is supported,836* otherwise <code>false</code>837*/838public static boolean isConversionSupported(AudioFormat.Encoding targetEncoding, AudioFormat sourceFormat) {839840841List codecs = getFormatConversionProviders();842843for(int i=0; i<codecs.size(); i++ ) {844FormatConversionProvider codec = (FormatConversionProvider) codecs.get(i);845if(codec.isConversionSupported(targetEncoding,sourceFormat) ) {846return true;847}848}849return false;850}851852853/**854* Obtains an audio input stream of the indicated encoding, by converting the855* provided audio input stream.856* @param targetEncoding the desired encoding after conversion857* @param sourceStream the stream to be converted858* @return an audio input stream of the indicated encoding859* @throws IllegalArgumentException if the conversion is not supported860* @see #getTargetEncodings(AudioFormat.Encoding)861* @see #getTargetEncodings(AudioFormat)862* @see #isConversionSupported(AudioFormat.Encoding, AudioFormat)863* @see #getAudioInputStream(AudioFormat, AudioInputStream)864*/865public static AudioInputStream getAudioInputStream(AudioFormat.Encoding targetEncoding,866AudioInputStream sourceStream) {867868List codecs = getFormatConversionProviders();869870for(int i = 0; i < codecs.size(); i++) {871FormatConversionProvider codec = (FormatConversionProvider) codecs.get(i);872if( codec.isConversionSupported( targetEncoding, sourceStream.getFormat() ) ) {873return codec.getAudioInputStream( targetEncoding, sourceStream );874}875}876// we ran out of options, throw an exception877throw new IllegalArgumentException("Unsupported conversion: " + targetEncoding + " from " + sourceStream.getFormat());878}879880881/**882* Obtains the formats that have a particular encoding and that the system can883* obtain from a stream of the specified format using the set of884* installed format converters.885* @param targetEncoding the desired encoding after conversion886* @param sourceFormat the audio format before conversion887* @return array of formats. If no formats of the specified888* encoding are supported, an array of length 0 is returned.889*/890public static AudioFormat[] getTargetFormats(AudioFormat.Encoding targetEncoding, AudioFormat sourceFormat) {891892List codecs = getFormatConversionProviders();893Vector formats = new Vector();894895int size = 0;896int index = 0;897AudioFormat fmts[] = null;898899// gather from all the codecs900901for(int i=0; i<codecs.size(); i++ ) {902FormatConversionProvider codec = (FormatConversionProvider) codecs.get(i);903fmts = codec.getTargetFormats(targetEncoding, sourceFormat);904size += fmts.length;905formats.addElement( fmts );906}907908// now build a new array909910AudioFormat fmts2[] = new AudioFormat[size];911for(int i=0; i<formats.size(); i++ ) {912fmts = (AudioFormat [])(formats.get(i));913for(int j=0; j<fmts.length; j++ ) {914fmts2[index++] = fmts[j];915}916}917return fmts2;918}919920921/**922* Indicates whether an audio input stream of a specified format923* can be obtained from an audio input stream of another specified format.924* @param targetFormat the desired audio format after conversion925* @param sourceFormat the audio format before conversion926* @return <code>true</code> if the conversion is supported,927* otherwise <code>false</code>928*/929930public static boolean isConversionSupported(AudioFormat targetFormat, AudioFormat sourceFormat) {931932List codecs = getFormatConversionProviders();933934for(int i=0; i<codecs.size(); i++ ) {935FormatConversionProvider codec = (FormatConversionProvider) codecs.get(i);936if(codec.isConversionSupported(targetFormat, sourceFormat) ) {937return true;938}939}940return false;941}942943944/**945* Obtains an audio input stream of the indicated format, by converting the946* provided audio input stream.947* @param targetFormat the desired audio format after conversion948* @param sourceStream the stream to be converted949* @return an audio input stream of the indicated format950* @throws IllegalArgumentException if the conversion is not supported951* #see #getTargetEncodings(AudioFormat)952* @see #getTargetFormats(AudioFormat.Encoding, AudioFormat)953* @see #isConversionSupported(AudioFormat, AudioFormat)954* @see #getAudioInputStream(AudioFormat.Encoding, AudioInputStream)955*/956public static AudioInputStream getAudioInputStream(AudioFormat targetFormat,957AudioInputStream sourceStream) {958959if (sourceStream.getFormat().matches(targetFormat)) {960return sourceStream;961}962963List codecs = getFormatConversionProviders();964965for(int i = 0; i < codecs.size(); i++) {966FormatConversionProvider codec = (FormatConversionProvider) codecs.get(i);967if(codec.isConversionSupported(targetFormat,sourceStream.getFormat()) ) {968return codec.getAudioInputStream(targetFormat,sourceStream);969}970}971972// we ran out of options...973throw new IllegalArgumentException("Unsupported conversion: " + targetFormat + " from " + sourceStream.getFormat());974}975976977/**978* Obtains the audio file format of the provided input stream. The stream must979* point to valid audio file data. The implementation of this method may require980* multiple parsers to examine the stream to determine whether they support it.981* These parsers must be able to mark the stream, read enough data to determine whether they982* support the stream, and, if not, reset the stream's read pointer to its original983* position. If the input stream does not support these operations, this method may fail984* with an <code>IOException</code>.985* @param stream the input stream from which file format information should be986* extracted987* @return an <code>AudioFileFormat</code> object describing the stream's audio file format988* @throws UnsupportedAudioFileException if the stream does not point to valid audio989* file data recognized by the system990* @throws IOException if an input/output exception occurs991* @see InputStream#markSupported992* @see InputStream#mark993*/994public static AudioFileFormat getAudioFileFormat(InputStream stream)995throws UnsupportedAudioFileException, IOException {996997List providers = getAudioFileReaders();998AudioFileFormat format = null;9991000for(int i = 0; i < providers.size(); i++ ) {1001AudioFileReader reader = (AudioFileReader) providers.get(i);1002try {1003format = reader.getAudioFileFormat( stream ); // throws IOException1004break;1005} catch (UnsupportedAudioFileException e) {1006continue;1007}1008}10091010if( format==null ) {1011throw new UnsupportedAudioFileException("file is not a supported file type");1012} else {1013return format;1014}1015}10161017/**1018* Obtains the audio file format of the specified URL. The URL must1019* point to valid audio file data.1020* @param url the URL from which file format information should be1021* extracted1022* @return an <code>AudioFileFormat</code> object describing the audio file format1023* @throws UnsupportedAudioFileException if the URL does not point to valid audio1024* file data recognized by the system1025* @throws IOException if an input/output exception occurs1026*/1027public static AudioFileFormat getAudioFileFormat(URL url)1028throws UnsupportedAudioFileException, IOException {10291030List providers = getAudioFileReaders();1031AudioFileFormat format = null;10321033for(int i = 0; i < providers.size(); i++ ) {1034AudioFileReader reader = (AudioFileReader) providers.get(i);1035try {1036format = reader.getAudioFileFormat( url ); // throws IOException1037break;1038} catch (UnsupportedAudioFileException e) {1039continue;1040}1041}10421043if( format==null ) {1044throw new UnsupportedAudioFileException("file is not a supported file type");1045} else {1046return format;1047}1048}10491050/**1051* Obtains the audio file format of the specified <code>File</code>. The <code>File</code> must1052* point to valid audio file data.1053* @param file the <code>File</code> from which file format information should be1054* extracted1055* @return an <code>AudioFileFormat</code> object describing the audio file format1056* @throws UnsupportedAudioFileException if the <code>File</code> does not point to valid audio1057* file data recognized by the system1058* @throws IOException if an I/O exception occurs1059*/1060public static AudioFileFormat getAudioFileFormat(File file)1061throws UnsupportedAudioFileException, IOException {10621063List providers = getAudioFileReaders();1064AudioFileFormat format = null;10651066for(int i = 0; i < providers.size(); i++ ) {1067AudioFileReader reader = (AudioFileReader) providers.get(i);1068try {1069format = reader.getAudioFileFormat( file ); // throws IOException1070break;1071} catch (UnsupportedAudioFileException e) {1072continue;1073}1074}10751076if( format==null ) {1077throw new UnsupportedAudioFileException("file is not a supported file type");1078} else {1079return format;1080}1081}108210831084/**1085* Obtains an audio input stream from the provided input stream. The stream must1086* point to valid audio file data. The implementation of this method may1087* require multiple parsers to1088* examine the stream to determine whether they support it. These parsers must1089* be able to mark the stream, read enough data to determine whether they1090* support the stream, and, if not, reset the stream's read pointer to its original1091* position. If the input stream does not support these operation, this method may fail1092* with an <code>IOException</code>.1093* @param stream the input stream from which the <code>AudioInputStream</code> should be1094* constructed1095* @return an <code>AudioInputStream</code> object based on the audio file data contained1096* in the input stream.1097* @throws UnsupportedAudioFileException if the stream does not point to valid audio1098* file data recognized by the system1099* @throws IOException if an I/O exception occurs1100* @see InputStream#markSupported1101* @see InputStream#mark1102*/1103public static AudioInputStream getAudioInputStream(InputStream stream)1104throws UnsupportedAudioFileException, IOException {11051106List providers = getAudioFileReaders();1107AudioInputStream audioStream = null;11081109for(int i = 0; i < providers.size(); i++ ) {1110AudioFileReader reader = (AudioFileReader) providers.get(i);1111try {1112audioStream = reader.getAudioInputStream( stream ); // throws IOException1113break;1114} catch (UnsupportedAudioFileException e) {1115continue;1116}1117}11181119if( audioStream==null ) {1120throw new UnsupportedAudioFileException("could not get audio input stream from input stream");1121} else {1122return audioStream;1123}1124}11251126/**1127* Obtains an audio input stream from the URL provided. The URL must1128* point to valid audio file data.1129* @param url the URL for which the <code>AudioInputStream</code> should be1130* constructed1131* @return an <code>AudioInputStream</code> object based on the audio file data pointed1132* to by the URL1133* @throws UnsupportedAudioFileException if the URL does not point to valid audio1134* file data recognized by the system1135* @throws IOException if an I/O exception occurs1136*/1137public static AudioInputStream getAudioInputStream(URL url)1138throws UnsupportedAudioFileException, IOException {11391140List providers = getAudioFileReaders();1141AudioInputStream audioStream = null;11421143for(int i = 0; i < providers.size(); i++ ) {1144AudioFileReader reader = (AudioFileReader) providers.get(i);1145try {1146audioStream = reader.getAudioInputStream( url ); // throws IOException1147break;1148} catch (UnsupportedAudioFileException e) {1149continue;1150}1151}11521153if( audioStream==null ) {1154throw new UnsupportedAudioFileException("could not get audio input stream from input URL");1155} else {1156return audioStream;1157}1158}11591160/**1161* Obtains an audio input stream from the provided <code>File</code>. The <code>File</code> must1162* point to valid audio file data.1163* @param file the <code>File</code> for which the <code>AudioInputStream</code> should be1164* constructed1165* @return an <code>AudioInputStream</code> object based on the audio file data pointed1166* to by the <code>File</code>1167* @throws UnsupportedAudioFileException if the <code>File</code> does not point to valid audio1168* file data recognized by the system1169* @throws IOException if an I/O exception occurs1170*/1171public static AudioInputStream getAudioInputStream(File file)1172throws UnsupportedAudioFileException, IOException {11731174List providers = getAudioFileReaders();1175AudioInputStream audioStream = null;11761177for(int i = 0; i < providers.size(); i++ ) {1178AudioFileReader reader = (AudioFileReader) providers.get(i);1179try {1180audioStream = reader.getAudioInputStream( file ); // throws IOException1181break;1182} catch (UnsupportedAudioFileException e) {1183continue;1184}1185}11861187if( audioStream==null ) {1188throw new UnsupportedAudioFileException("could not get audio input stream from input file");1189} else {1190return audioStream;1191}1192}119311941195/**1196* Obtains the file types for which file writing support is provided by the system.1197* @return array of unique file types. If no file types are supported,1198* an array of length 0 is returned.1199*/1200public static AudioFileFormat.Type[] getAudioFileTypes() {1201List providers = getAudioFileWriters();1202Set returnTypesSet = new HashSet();12031204for(int i=0; i < providers.size(); i++) {1205AudioFileWriter writer = (AudioFileWriter) providers.get(i);1206AudioFileFormat.Type[] fileTypes = writer.getAudioFileTypes();1207for(int j=0; j < fileTypes.length; j++) {1208returnTypesSet.add(fileTypes[j]);1209}1210}1211AudioFileFormat.Type returnTypes[] = (AudioFileFormat.Type[])1212returnTypesSet.toArray(new AudioFileFormat.Type[0]);1213return returnTypes;1214}121512161217/**1218* Indicates whether file writing support for the specified file type is provided1219* by the system.1220* @param fileType the file type for which write capabilities are queried1221* @return <code>true</code> if the file type is supported,1222* otherwise <code>false</code>1223*/1224public static boolean isFileTypeSupported(AudioFileFormat.Type fileType) {12251226List providers = getAudioFileWriters();12271228for(int i=0; i < providers.size(); i++) {1229AudioFileWriter writer = (AudioFileWriter) providers.get(i);1230if (writer.isFileTypeSupported(fileType)) {1231return true;1232}1233}1234return false;1235}123612371238/**1239* Obtains the file types that the system can write from the1240* audio input stream specified.1241* @param stream the audio input stream for which audio file type support1242* is queried1243* @return array of file types. If no file types are supported,1244* an array of length 0 is returned.1245*/1246public static AudioFileFormat.Type[] getAudioFileTypes(AudioInputStream stream) {1247List providers = getAudioFileWriters();1248Set returnTypesSet = new HashSet();12491250for(int i=0; i < providers.size(); i++) {1251AudioFileWriter writer = (AudioFileWriter) providers.get(i);1252AudioFileFormat.Type[] fileTypes = writer.getAudioFileTypes(stream);1253for(int j=0; j < fileTypes.length; j++) {1254returnTypesSet.add(fileTypes[j]);1255}1256}1257AudioFileFormat.Type returnTypes[] = (AudioFileFormat.Type[])1258returnTypesSet.toArray(new AudioFileFormat.Type[0]);1259return returnTypes;1260}126112621263/**1264* Indicates whether an audio file of the specified file type can be written1265* from the indicated audio input stream.1266* @param fileType the file type for which write capabilities are queried1267* @param stream the stream for which file-writing support is queried1268* @return <code>true</code> if the file type is supported for this audio input stream,1269* otherwise <code>false</code>1270*/1271public static boolean isFileTypeSupported(AudioFileFormat.Type fileType,1272AudioInputStream stream) {12731274List providers = getAudioFileWriters();12751276for(int i=0; i < providers.size(); i++) {1277AudioFileWriter writer = (AudioFileWriter) providers.get(i);1278if(writer.isFileTypeSupported(fileType, stream)) {1279return true;1280}1281}1282return false;1283}128412851286/**1287* Writes a stream of bytes representing an audio file of the specified file type1288* to the output stream provided. Some file types require that1289* the length be written into the file header; such files cannot be written from1290* start to finish unless the length is known in advance. An attempt1291* to write a file of such a type will fail with an IOException if the length in1292* the audio file type is <code>AudioSystem.NOT_SPECIFIED</code>.1293*1294* @param stream the audio input stream containing audio data to be1295* written to the file1296* @param fileType the kind of audio file to write1297* @param out the stream to which the file data should be written1298* @return the number of bytes written to the output stream1299* @throws IOException if an input/output exception occurs1300* @throws IllegalArgumentException if the file type is not supported by1301* the system1302* @see #isFileTypeSupported1303* @see #getAudioFileTypes1304*/1305public static int write(AudioInputStream stream, AudioFileFormat.Type fileType,1306OutputStream out) throws IOException {13071308List providers = getAudioFileWriters();1309int bytesWritten = 0;1310boolean flag = false;13111312for(int i=0; i < providers.size(); i++) {1313AudioFileWriter writer = (AudioFileWriter) providers.get(i);1314try {1315bytesWritten = writer.write( stream, fileType, out ); // throws IOException1316flag = true;1317break;1318} catch (IllegalArgumentException e) {1319// thrown if this provider cannot write the sequence, try the next1320continue;1321}1322}1323if(!flag) {1324throw new IllegalArgumentException("could not write audio file: file type not supported: " + fileType);1325} else {1326return bytesWritten;1327}1328}132913301331/**1332* Writes a stream of bytes representing an audio file of the specified file type1333* to the external file provided.1334* @param stream the audio input stream containing audio data to be1335* written to the file1336* @param fileType the kind of audio file to write1337* @param out the external file to which the file data should be written1338* @return the number of bytes written to the file1339* @throws IOException if an I/O exception occurs1340* @throws IllegalArgumentException if the file type is not supported by1341* the system1342* @see #isFileTypeSupported1343* @see #getAudioFileTypes1344*/1345public static int write(AudioInputStream stream, AudioFileFormat.Type fileType,1346File out) throws IOException {13471348List providers = getAudioFileWriters();1349int bytesWritten = 0;1350boolean flag = false;13511352for(int i=0; i < providers.size(); i++) {1353AudioFileWriter writer = (AudioFileWriter) providers.get(i);1354try {1355bytesWritten = writer.write( stream, fileType, out ); // throws IOException1356flag = true;1357break;1358} catch (IllegalArgumentException e) {1359// thrown if this provider cannot write the sequence, try the next1360continue;1361}1362}1363if (!flag) {1364throw new IllegalArgumentException("could not write audio file: file type not supported: " + fileType);1365} else {1366return bytesWritten;1367}1368}136913701371// METHODS FOR INTERNAL IMPLEMENTATION USE13721373/**1374* Obtains the set of MixerProviders on the system.1375*/1376private static List getMixerProviders() {1377return getProviders(MixerProvider.class);1378}137913801381/**1382* Obtains the set of format converters (codecs, transcoders, etc.)1383* that are currently installed on the system.1384* @return an array of1385* {@link javax.sound.sampled.spi.FormatConversionProvider1386* FormatConversionProvider}1387* objects representing the available format converters. If no format1388* converters readers are available on the system, an array of length 0 is1389* returned.1390*/1391private static List getFormatConversionProviders() {1392return getProviders(FormatConversionProvider.class);1393}139413951396/**1397* Obtains the set of audio file readers that are currently installed on the system.1398* @return a List of1399* {@link javax.sound.sampled.spi.AudioFileReader1400* AudioFileReader}1401* objects representing the installed audio file readers. If no audio file1402* readers are available on the system, an empty List is returned.1403*/1404private static List getAudioFileReaders() {1405return getProviders(AudioFileReader.class);1406}140714081409/**1410* Obtains the set of audio file writers that are currently installed on the system.1411* @return a List of1412* {@link javax.sound.samples.spi.AudioFileWriter AudioFileWriter}1413* objects representing the available audio file writers. If no audio file1414* writers are available on the system, an empty List is returned.1415*/1416private static List getAudioFileWriters() {1417return getProviders(AudioFileWriter.class);1418}1419142014211422/** Attempts to locate and return a default Mixer that provides lines1423* of the specified type.1424*1425* @param providers the installed mixer providers1426* @param info The requested line type1427* TargetDataLine.class, Clip.class or Port.class.1428* @return a Mixer that matches the requirements, or null if no default mixer found1429*/1430private static Mixer getDefaultMixer(List providers, Line.Info info) {1431Class lineClass = info.getLineClass();1432String providerClassName = JDK13Services.getDefaultProviderClassName(lineClass);1433String instanceName = JDK13Services.getDefaultInstanceName(lineClass);1434Mixer mixer;14351436if (providerClassName != null) {1437MixerProvider defaultProvider = getNamedProvider(providerClassName, providers);1438if (defaultProvider != null) {1439if (instanceName != null) {1440mixer = getNamedMixer(instanceName, defaultProvider, info);1441if (mixer != null) {1442return mixer;1443}1444} else {1445mixer = getFirstMixer(defaultProvider, info,1446false /* mixing not required*/);1447if (mixer != null) {1448return mixer;1449}1450}14511452}1453}14541455/* Provider class not specified or1456provider class cannot be found, or1457provider class and instance specified and instance cannot be found or is not appropriate */1458if (instanceName != null) {1459mixer = getNamedMixer(instanceName, providers, info);1460if (mixer != null) {1461return mixer;1462}1463}146414651466/* No default are specified, or if something is specified, everything1467failed. */1468return null;1469}1470147114721473/** Return a MixerProvider of a given class from the list of1474MixerProviders.14751476This method never requires the returned Mixer to do mixing.1477@param providerClassName The class name of the provider to be returned.1478@param providers The list of MixerProviders that is searched.1479@return A MixerProvider of the requested class, or null if none is1480found.1481*/1482private static MixerProvider getNamedProvider(String providerClassName,1483List providers) {1484for(int i = 0; i < providers.size(); i++) {1485MixerProvider provider = (MixerProvider) providers.get(i);1486if (provider.getClass().getName().equals(providerClassName)) {1487return provider;1488}1489}1490return null;1491}149214931494/** Return a Mixer with a given name from a given MixerProvider.1495This method never requires the returned Mixer to do mixing.1496@param mixerName The name of the Mixer to be returned.1497@param provider The MixerProvider to check for Mixers.1498@param info The type of line the returned Mixer is required to1499support.15001501@return A Mixer matching the requirements, or null if none is found.1502*/1503private static Mixer getNamedMixer(String mixerName,1504MixerProvider provider,1505Line.Info info) {1506Mixer.Info[] infos = provider.getMixerInfo();1507for (int i = 0; i < infos.length; i++) {1508if (infos[i].getName().equals(mixerName)) {1509Mixer mixer = provider.getMixer(infos[i]);1510if (isAppropriateMixer(mixer, info, false)) {1511return mixer;1512}1513}1514}1515return null;1516}151715181519/** From a List of MixerProviders, return a Mixer with a given name.1520This method never requires the returned Mixer to do mixing.1521@param mixerName The name of the Mixer to be returned.1522@param providers The List of MixerProviders to check for Mixers.1523@param info The type of line the returned Mixer is required to1524support.1525@return A Mixer matching the requirements, or null if none is found.1526*/1527private static Mixer getNamedMixer(String mixerName,1528List providers,1529Line.Info info) {1530for(int i = 0; i < providers.size(); i++) {1531MixerProvider provider = (MixerProvider) providers.get(i);1532Mixer mixer = getNamedMixer(mixerName, provider, info);1533if (mixer != null) {1534return mixer;1535}1536}1537return null;1538}153915401541/** 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 to1544support.1545@param isMixingRequired If true, only Mixers that support mixing are1546returned for line types of SourceDataLine and Clip.15471548@return A Mixer that is considered appropriate, or null1549if none is found.1550*/1551private static Mixer getFirstMixer(MixerProvider provider,1552Line.Info info,1553boolean isMixingRequired) {1554Mixer.Info[] infos = provider.getMixerInfo();1555for (int j = 0; j < infos.length; j++) {1556Mixer mixer = provider.getMixer(infos[j]);1557if (isAppropriateMixer(mixer, info, isMixingRequired)) {1558return mixer;1559}1560}1561return null;1562}156315641565/** Checks if a Mixer is appropriate.1566A Mixer is considered appropriate if it support the given line type.1567If isMixingRequired is true and the line type is an output one1568(SourceDataLine, Clip), the mixer is appropriate if it supports1569at least 2 (concurrent) lines of the given type.15701571@return true if the mixer is considered appropriate according to the1572rules given above, false otherwise.1573*/1574private static boolean isAppropriateMixer(Mixer mixer,1575Line.Info lineInfo,1576boolean isMixingRequired) {1577if (! mixer.isLineSupported(lineInfo)) {1578return false;1579}1580Class lineClass = lineInfo.getLineClass();1581if (isMixingRequired1582&& (SourceDataLine.class.isAssignableFrom(lineClass) ||1583Clip.class.isAssignableFrom(lineClass))) {1584int maxLines = mixer.getMaxLines(lineInfo);1585return ((maxLines == NOT_SPECIFIED) || (maxLines > 1));1586}1587return true;1588}1589159015911592/**1593* Like getMixerInfo, but return List1594*/1595private static List getMixerInfoList() {1596List providers = getMixerProviders();1597return getMixerInfoList(providers);1598}159916001601/**1602* Like getMixerInfo, but return List1603*/1604private static List getMixerInfoList(List providers) {1605List infos = new ArrayList();16061607Mixer.Info[] someInfos; // per-mixer1608Mixer.Info[] allInfos; // for all mixers16091610for(int i = 0; i < providers.size(); i++ ) {1611someInfos = (Mixer.Info[])1612((MixerProvider)providers.get(i)).getMixerInfo();16131614for (int j = 0; j < someInfos.length; j++) {1615infos.add(someInfos[j]);1616}1617}16181619return infos;1620}162116221623/**1624* Obtains the set of services currently installed on the system1625* using sun.misc.Service, the SPI mechanism in 1.3.1626* @return a List of instances of providers for the requested service.1627* If no providers are available, a vector of length 0 will be returned.1628*/1629private static List getProviders(Class providerClass) {1630return JDK13Services.getProviders(providerClass);1631}1632}163316341635