src/share/classes/javax/sound/sampled/AudioSystem.java

Print this page




 179      * methods may also accept or return this value, as documented.
 180      */
 181     public static final int NOT_SPECIFIED = -1;
 182 
 183     /**
 184      * Private no-args constructor for ensuring against instantiation.
 185      */
 186     private AudioSystem() {
 187     }
 188 
 189 
 190     /**
 191      * Obtains an array of mixer info objects that represents
 192      * the set of audio mixers that are currently installed on the system.
 193      * @return an array of info objects for the currently installed mixers.  If no mixers
 194      * are available on the system, an array of length 0 is returned.
 195      * @see #getMixer
 196      */
 197     public static Mixer.Info[] getMixerInfo() {
 198 
 199         List infos = getMixerInfoList();
 200         Mixer.Info[] allInfos = (Mixer.Info[]) infos.toArray(new Mixer.Info[infos.size()]);
 201         return allInfos;
 202     }
 203 
 204 
 205     /**
 206      * Obtains the requested audio mixer.
 207      * @param info a <code>Mixer.Info</code> object representing the desired
 208      * mixer, or <code>null</code> for the system default mixer
 209      * @return the requested mixer
 210      * @throws SecurityException if the requested mixer
 211      * is unavailable because of security restrictions
 212      * @throws IllegalArgumentException if the info object does not represent
 213      * a mixer installed on the system
 214      * @see #getMixerInfo
 215      */
 216     public static Mixer getMixer(Mixer.Info info) {
 217 
 218         Mixer mixer = null;
 219         List providers = getMixerProviders();
 220 
 221         for(int i = 0; i < providers.size(); i++ ) {
 222 
 223             try {
 224                 return ((MixerProvider)providers.get(i)).getMixer(info);
 225 
 226             } catch (IllegalArgumentException e) {
 227             } catch (NullPointerException e) {
 228                 // $$jb 08.20.99:  If the strings in the info object aren't
 229                 // set, then Netscape (using jdk1.1.5) tends to throw
 230                 // NPE's when doing some string manipulation.  This is
 231                 // probably not the best fix, but is solves the problem
 232                 // of the NPE in Netscape using local classes
 233                 // $$jb 11.01.99: Replacing this patch.
 234             }
 235         }
 236 
 237         //$$fb if looking for default mixer, and not found yet, add a round of looking
 238         if (info == null) {
 239             for(int i = 0; i < providers.size(); i++ ) {
 240                 try {
 241                     MixerProvider provider = (MixerProvider) providers.get(i);
 242                     Mixer.Info[] infos = provider.getMixerInfo();
 243                     // start from 0 to last device (do not reverse this order)
 244                     for (int ii = 0; ii < infos.length; ii++) {
 245                         try {
 246                             return provider.getMixer(infos[ii]);
 247                         } catch (IllegalArgumentException e) {
 248                             // this is not a good default device :)
 249                         }
 250                     }
 251                 } catch (IllegalArgumentException e) {
 252                 } catch (NullPointerException e) {
 253                 }
 254             }
 255         }
 256 
 257 
 258         throw new IllegalArgumentException("Mixer not supported: "
 259                                            + (info!=null?info.toString():"null"));
 260     }
 261 
 262 
 263     //$$fb 2002-11-26: fix for 4757930: DOC: AudioSystem.getTarget/SourceLineInfo() is ambiguous
 264     /**
 265      * Obtains information about all source lines of a particular type that are supported
 266      * by the installed mixers.
 267      * @param info a <code>Line.Info</code> object that specifies the kind of
 268      * lines about which information is requested
 269      * @return an array of <code>Line.Info</code> objects describing source lines matching
 270      * the type requested.  If no matching source lines are supported, an array of length 0
 271      * is returned.
 272      *
 273      * @see Mixer#getSourceLineInfo(Line.Info)
 274      */
 275     public static Line.Info[] getSourceLineInfo(Line.Info info) {
 276 
 277         Vector vector = new Vector();
 278         Line.Info[] currentInfoArray;
 279 
 280         Mixer mixer;
 281         Line.Info fullInfo = null;
 282         Mixer.Info[] infoArray = getMixerInfo();
 283 
 284         for (int i = 0; i < infoArray.length; i++) {
 285 
 286             mixer = getMixer(infoArray[i]);
 287 
 288             currentInfoArray = mixer.getSourceLineInfo(info);
 289             for (int j = 0; j < currentInfoArray.length; j++) {
 290                 vector.addElement(currentInfoArray[j]);
 291             }
 292         }
 293 
 294         Line.Info[] returnedArray = new Line.Info[vector.size()];
 295 
 296         for (int i = 0; i < returnedArray.length; i++) {
 297             returnedArray[i] = (Line.Info)vector.get(i);
 298         }
 299 
 300         return returnedArray;
 301     }
 302 
 303 
 304     /**
 305      * Obtains information about all target lines of a particular type that are supported
 306      * by the installed mixers.
 307      * @param info a <code>Line.Info</code> object that specifies the kind of
 308      * lines about which information is requested
 309      * @return an array of <code>Line.Info</code> objects describing target lines matching
 310      * the type requested.  If no matching target lines are supported, an array of length 0
 311      * is returned.
 312      *
 313      * @see Mixer#getTargetLineInfo(Line.Info)
 314      */
 315     public static Line.Info[] getTargetLineInfo(Line.Info info) {
 316 
 317         Vector vector = new Vector();
 318         Line.Info[] currentInfoArray;
 319 
 320         Mixer mixer;
 321         Line.Info fullInfo = null;
 322         Mixer.Info[] infoArray = getMixerInfo();
 323 
 324         for (int i = 0; i < infoArray.length; i++) {
 325 
 326             mixer = getMixer(infoArray[i]);
 327 
 328             currentInfoArray = mixer.getTargetLineInfo(info);
 329             for (int j = 0; j < currentInfoArray.length; j++) {
 330                 vector.addElement(currentInfoArray[j]);
 331             }
 332         }
 333 
 334         Line.Info[] returnedArray = new Line.Info[vector.size()];
 335 
 336         for (int i = 0; i < returnedArray.length; i++) {
 337             returnedArray[i] = (Line.Info)vector.get(i);
 338         }
 339 
 340         return returnedArray;
 341     }
 342 
 343 
 344     /**
 345      * Indicates whether the system supports any lines that match
 346      * the specified <code>Line.Info</code> object.  A line is supported if
 347      * any installed mixer supports it.
 348      * @param info a <code>Line.Info</code> object describing the line for which support is queried
 349      * @return <code>true</code> if at least one matching line is
 350      * supported, otherwise <code>false</code>
 351      *
 352      * @see Mixer#isLineSupported(Line.Info)
 353      */
 354     public static boolean isLineSupported(Line.Info info) {
 355 
 356         Mixer mixer;
 357         Mixer.Info[] infoArray = getMixerInfo();


 391      * If the respective property is not set, or the mixer
 392      * requested in the property is not installed or does not provide the
 393      * requested line, all installed mixers are queried for the
 394      * requested line type. A Line will be returned from the first mixer
 395      * providing the requested line type.
 396      *
 397      * @param info a <code>Line.Info</code> object describing the desired kind of line
 398      * @return a line of the requested kind
 399      *
 400      * @throws LineUnavailableException if a matching line
 401      * is not available due to resource restrictions
 402      * @throws SecurityException if a matching line
 403      * is not available due to security restrictions
 404      * @throws IllegalArgumentException if the system does not
 405      * support at least one line matching the specified
 406      * <code>Line.Info</code> object
 407      * through any installed mixer
 408      */
 409     public static Line getLine(Line.Info info) throws LineUnavailableException {
 410         LineUnavailableException lue = null;
 411         List providers = getMixerProviders();
 412 
 413 
 414         // 1: try from default mixer for this line class
 415         try {
 416             Mixer mixer = getDefaultMixer(providers, info);
 417             if (mixer != null && mixer.isLineSupported(info)) {
 418                 return mixer.getLine(info);
 419             }
 420         } catch (LineUnavailableException e) {
 421             lue = e;
 422         } catch (IllegalArgumentException iae) {
 423             // must not happen... but better to catch it here,
 424             // if plug-ins are badly written
 425         }
 426 
 427 
 428         // 2: if that doesn't work, try to find any mixing mixer
 429         for(int i = 0; i < providers.size(); i++) {
 430             MixerProvider provider = (MixerProvider) providers.get(i);
 431             Mixer.Info[] infos = provider.getMixerInfo();
 432 
 433             for (int j = 0; j < infos.length; j++) {
 434                 try {
 435                     Mixer mixer = provider.getMixer(infos[j]);
 436                     // see if this is an appropriate mixer which can mix
 437                     if (isAppropriateMixer(mixer, info, true)) {
 438                         return mixer.getLine(info);
 439                     }
 440                 } catch (LineUnavailableException e) {
 441                     lue = e;
 442                 } catch (IllegalArgumentException iae) {
 443                     // must not happen... but better to catch it here,
 444                     // if plug-ins are badly written
 445                 }
 446             }
 447         }
 448 
 449 
 450         // 3: if that didn't work, try to find any non-mixing mixer
 451         for(int i = 0; i < providers.size(); i++) {
 452             MixerProvider provider = (MixerProvider) providers.get(i);
 453             Mixer.Info[] infos = provider.getMixerInfo();
 454             for (int j = 0; j < infos.length; j++) {
 455                 try {
 456                     Mixer mixer = provider.getMixer(infos[j]);
 457                     // see if this is an appropriate mixer which can mix
 458                     if (isAppropriateMixer(mixer, info, false)) {
 459                         return mixer.getLine(info);
 460                     }
 461                 } catch (LineUnavailableException e) {
 462                     lue = e;
 463                 } catch (IllegalArgumentException iae) {
 464                     // must not happen... but better to catch it here,
 465                     // if plug-ins are badly written
 466                 }
 467             }
 468         }
 469 
 470         // if this line was supported but was not available, throw the last
 471         // LineUnavailableException we got (??).
 472         if (lue != null) {


 747 
 748         DataLine.Info info = new DataLine.Info(TargetDataLine.class, format);
 749         Mixer mixer = AudioSystem.getMixer(mixerinfo);
 750         return (TargetDataLine) mixer.getLine(info);
 751     }
 752 
 753 
 754     // $$fb 2002-04-12: fix for 4662082: behavior of AudioSystem.getTargetEncodings() methods doesn't match the spec
 755     /**
 756      * Obtains the encodings that the system can obtain from an
 757      * audio input stream with the specified encoding using the set
 758      * of installed format converters.
 759      * @param sourceEncoding the encoding for which conversion support
 760      * is queried
 761      * @return array of encodings.  If <code>sourceEncoding</code>is not supported,
 762      * an array of length 0 is returned. Otherwise, the array will have a length
 763      * of at least 1, representing <code>sourceEncoding</code> (no conversion).
 764      */
 765     public static AudioFormat.Encoding[] getTargetEncodings(AudioFormat.Encoding sourceEncoding) {
 766 
 767         List codecs = getFormatConversionProviders();
 768         Vector encodings = new Vector();
 769 
 770         AudioFormat.Encoding encs[] = null;
 771 
 772         // gather from all the codecs
 773         for(int i=0; i<codecs.size(); i++ ) {
 774             FormatConversionProvider codec = (FormatConversionProvider) codecs.get(i);
 775             if( codec.isSourceEncodingSupported( sourceEncoding ) ) {
 776                 encs = codec.getTargetEncodings();
 777                 for (int j = 0; j < encs.length; j++) {
 778                     encodings.addElement( encs[j] );
 779                 }
 780             }
 781         }
 782         AudioFormat.Encoding encs2[] = (AudioFormat.Encoding[]) encodings.toArray(new AudioFormat.Encoding[0]);
 783         return encs2;
 784     }
 785 
 786 
 787 
 788     // $$fb 2002-04-12: fix for 4662082: behavior of AudioSystem.getTargetEncodings() methods doesn't match the spec
 789     /**
 790      * Obtains the encodings that the system can obtain from an
 791      * audio input stream with the specified format using the set
 792      * of installed format converters.
 793      * @param sourceFormat the audio format for which conversion
 794      * is queried
 795      * @return array of encodings. If <code>sourceFormat</code>is not supported,
 796      * an array of length 0 is returned. Otherwise, the array will have a length
 797      * of at least 1, representing the encoding of <code>sourceFormat</code> (no conversion).
 798      */
 799     public static AudioFormat.Encoding[] getTargetEncodings(AudioFormat sourceFormat) {
 800 
 801 
 802         List codecs = getFormatConversionProviders();
 803         Vector encodings = new Vector();
 804 
 805         int size = 0;
 806         int index = 0;
 807         AudioFormat.Encoding encs[] = null;
 808 
 809         // gather from all the codecs
 810 
 811         for(int i=0; i<codecs.size(); i++ ) {
 812             encs = ((FormatConversionProvider) codecs.get(i)).getTargetEncodings(sourceFormat);
 813             size += encs.length;
 814             encodings.addElement( encs );
 815         }
 816 
 817         // now build a new array
 818 
 819         AudioFormat.Encoding encs2[] = new AudioFormat.Encoding[size];
 820         for(int i=0; i<encodings.size(); i++ ) {
 821             encs = (AudioFormat.Encoding [])(encodings.get(i));
 822             for(int j=0; j<encs.length; j++ ) {
 823                 encs2[index++] = encs[j];
 824             }
 825         }
 826         return encs2;
 827     }
 828 
 829 
 830     /**
 831      * Indicates whether an audio input stream of the specified encoding
 832      * can be obtained from an audio input stream that has the specified
 833      * format.
 834      * @param targetEncoding the desired encoding after conversion
 835      * @param sourceFormat the audio format before conversion
 836      * @return <code>true</code> if the conversion is supported,
 837      * otherwise <code>false</code>
 838      */
 839     public static boolean isConversionSupported(AudioFormat.Encoding targetEncoding, AudioFormat sourceFormat) {
 840 
 841 
 842         List codecs = getFormatConversionProviders();
 843 
 844         for(int i=0; i<codecs.size(); i++ ) {
 845             FormatConversionProvider codec = (FormatConversionProvider) codecs.get(i);
 846             if(codec.isConversionSupported(targetEncoding,sourceFormat) ) {
 847                 return true;
 848             }
 849         }
 850         return false;
 851     }
 852 
 853 
 854     /**
 855      * Obtains an audio input stream of the indicated encoding, by converting the
 856      * provided audio input stream.
 857      * @param targetEncoding the desired encoding after conversion
 858      * @param sourceStream the stream to be converted
 859      * @return an audio input stream of the indicated encoding
 860      * @throws IllegalArgumentException if the conversion is not supported
 861      * @see #getTargetEncodings(AudioFormat.Encoding)
 862      * @see #getTargetEncodings(AudioFormat)
 863      * @see #isConversionSupported(AudioFormat.Encoding, AudioFormat)
 864      * @see #getAudioInputStream(AudioFormat, AudioInputStream)
 865      */
 866     public static AudioInputStream getAudioInputStream(AudioFormat.Encoding targetEncoding,
 867                                                        AudioInputStream sourceStream) {
 868 
 869         List codecs = getFormatConversionProviders();
 870 
 871         for(int i = 0; i < codecs.size(); i++) {
 872             FormatConversionProvider codec = (FormatConversionProvider) codecs.get(i);
 873             if( codec.isConversionSupported( targetEncoding, sourceStream.getFormat() ) ) {
 874                 return codec.getAudioInputStream( targetEncoding, sourceStream );
 875             }
 876         }
 877         // we ran out of options, throw an exception
 878         throw new IllegalArgumentException("Unsupported conversion: " + targetEncoding + " from " + sourceStream.getFormat());
 879     }
 880 
 881 
 882     /**
 883      * Obtains the formats that have a particular encoding and that the system can
 884      * obtain from a stream of the specified format using the set of
 885      * installed format converters.
 886      * @param targetEncoding the desired encoding after conversion
 887      * @param sourceFormat the audio format before conversion
 888      * @return array of formats.  If no formats of the specified
 889      * encoding are supported, an array of length 0 is returned.
 890      */
 891     public static AudioFormat[] getTargetFormats(AudioFormat.Encoding targetEncoding, AudioFormat sourceFormat) {
 892 
 893         List codecs = getFormatConversionProviders();
 894         Vector formats = new Vector();
 895 
 896         int size = 0;
 897         int index = 0;
 898         AudioFormat fmts[] = null;
 899 
 900         // gather from all the codecs
 901 
 902         for(int i=0; i<codecs.size(); i++ ) {
 903             FormatConversionProvider codec = (FormatConversionProvider) codecs.get(i);
 904             fmts = codec.getTargetFormats(targetEncoding, sourceFormat);
 905             size += fmts.length;
 906             formats.addElement( fmts );
 907         }
 908 
 909         // now build a new array
 910 
 911         AudioFormat fmts2[] = new AudioFormat[size];
 912         for(int i=0; i<formats.size(); i++ ) {
 913             fmts = (AudioFormat [])(formats.get(i));
 914             for(int j=0; j<fmts.length; j++ ) {
 915                 fmts2[index++] = fmts[j];
 916             }
 917         }
 918         return fmts2;
 919     }
 920 
 921 
 922     /**
 923      * Indicates whether an audio input stream of a specified format
 924      * can be obtained from an audio input stream of another specified format.
 925      * @param targetFormat the desired audio format after conversion
 926      * @param sourceFormat the audio format before conversion
 927      * @return <code>true</code> if the conversion is supported,
 928      * otherwise <code>false</code>
 929      */
 930 
 931     public static boolean isConversionSupported(AudioFormat targetFormat, AudioFormat sourceFormat) {
 932 
 933         List codecs = getFormatConversionProviders();
 934 
 935         for(int i=0; i<codecs.size(); i++ ) {
 936             FormatConversionProvider codec = (FormatConversionProvider) codecs.get(i);
 937             if(codec.isConversionSupported(targetFormat, sourceFormat) ) {
 938                 return true;
 939             }
 940         }
 941         return false;
 942     }
 943 
 944 
 945     /**
 946      * Obtains an audio input stream of the indicated format, by converting the
 947      * provided audio input stream.
 948      * @param targetFormat the desired audio format after conversion
 949      * @param sourceStream the stream to be converted
 950      * @return an audio input stream of the indicated format
 951      * @throws IllegalArgumentException if the conversion is not supported
 952      * #see #getTargetEncodings(AudioFormat)
 953      * @see #getTargetFormats(AudioFormat.Encoding, AudioFormat)
 954      * @see #isConversionSupported(AudioFormat, AudioFormat)
 955      * @see #getAudioInputStream(AudioFormat.Encoding, AudioInputStream)
 956      */
 957     public static AudioInputStream getAudioInputStream(AudioFormat targetFormat,
 958                                                        AudioInputStream sourceStream) {
 959 
 960         if (sourceStream.getFormat().matches(targetFormat)) {
 961             return sourceStream;
 962         }
 963 
 964         List codecs = getFormatConversionProviders();
 965 
 966         for(int i = 0; i < codecs.size(); i++) {
 967             FormatConversionProvider codec = (FormatConversionProvider) codecs.get(i);
 968             if(codec.isConversionSupported(targetFormat,sourceStream.getFormat()) ) {
 969                 return codec.getAudioInputStream(targetFormat,sourceStream);
 970             }
 971         }
 972 
 973         // we ran out of options...
 974         throw new IllegalArgumentException("Unsupported conversion: " + targetFormat + " from " + sourceStream.getFormat());
 975     }
 976 
 977 
 978     /**
 979      * Obtains the audio file format of the provided input stream.  The stream must
 980      * point to valid audio file data.  The implementation of this method may require
 981      * multiple parsers to examine the stream to determine whether they support it.
 982      * These parsers must be able to mark the stream, read enough data to determine whether they
 983      * support the stream, and, if not, reset the stream's read pointer to its original
 984      * position.  If the input stream does not support these operations, this method may fail
 985      * with an <code>IOException</code>.
 986      * @param stream the input stream from which file format information should be
 987      * extracted
 988      * @return an <code>AudioFileFormat</code> object describing the stream's audio file format
 989      * @throws UnsupportedAudioFileException if the stream does not point to valid audio
 990      * file data recognized by the system
 991      * @throws IOException if an input/output exception occurs
 992      * @see InputStream#markSupported
 993      * @see InputStream#mark
 994      */
 995     public static AudioFileFormat getAudioFileFormat(InputStream stream)
 996         throws UnsupportedAudioFileException, IOException {
 997 
 998         List providers = getAudioFileReaders();
 999         AudioFileFormat format = null;
1000 
1001         for(int i = 0; i < providers.size(); i++ ) {
1002             AudioFileReader reader = (AudioFileReader) providers.get(i);
1003             try {
1004                 format = reader.getAudioFileFormat( stream ); // throws IOException
1005                 break;
1006             } catch (UnsupportedAudioFileException e) {
1007                 continue;
1008             }
1009         }
1010 
1011         if( format==null ) {
1012             throw new UnsupportedAudioFileException("file is not a supported file type");
1013         } else {
1014             return format;
1015         }
1016     }
1017 
1018     /**
1019      * Obtains the audio file format of the specified URL.  The URL must
1020      * point to valid audio file data.
1021      * @param url the URL from which file format information should be
1022      * extracted
1023      * @return an <code>AudioFileFormat</code> object describing the audio file format
1024      * @throws UnsupportedAudioFileException if the URL does not point to valid audio
1025      * file data recognized by the system
1026      * @throws IOException if an input/output exception occurs
1027      */
1028     public static AudioFileFormat getAudioFileFormat(URL url)
1029         throws UnsupportedAudioFileException, IOException {
1030 
1031         List providers = getAudioFileReaders();
1032         AudioFileFormat format = null;
1033 
1034         for(int i = 0; i < providers.size(); i++ ) {
1035             AudioFileReader reader = (AudioFileReader) providers.get(i);
1036             try {
1037                 format = reader.getAudioFileFormat( url ); // throws IOException
1038                 break;
1039             } catch (UnsupportedAudioFileException e) {
1040                 continue;
1041             }
1042         }
1043 
1044         if( format==null ) {
1045             throw new UnsupportedAudioFileException("file is not a supported file type");
1046         } else {
1047             return format;
1048         }
1049     }
1050 
1051     /**
1052      * Obtains the audio file format of the specified <code>File</code>.  The <code>File</code> must
1053      * point to valid audio file data.
1054      * @param file the <code>File</code> from which file format information should be
1055      * extracted
1056      * @return an <code>AudioFileFormat</code> object describing the audio file format
1057      * @throws UnsupportedAudioFileException if the <code>File</code> does not point to valid audio
1058      * file data recognized by the system
1059      * @throws IOException if an I/O exception occurs
1060      */
1061     public static AudioFileFormat getAudioFileFormat(File file)
1062         throws UnsupportedAudioFileException, IOException {
1063 
1064         List providers = getAudioFileReaders();
1065         AudioFileFormat format = null;
1066 
1067         for(int i = 0; i < providers.size(); i++ ) {
1068             AudioFileReader reader = (AudioFileReader) providers.get(i);
1069             try {
1070                 format = reader.getAudioFileFormat( file ); // throws IOException
1071                 break;
1072             } catch (UnsupportedAudioFileException e) {
1073                 continue;
1074             }
1075         }
1076 
1077         if( format==null ) {
1078             throw new UnsupportedAudioFileException("file is not a supported file type");
1079         } else {
1080             return format;
1081         }
1082     }
1083 
1084 
1085     /**
1086      * Obtains an audio input stream from the provided input stream.  The stream must
1087      * point to valid audio file data.  The implementation of this method may
1088      * require multiple parsers to
1089      * examine the stream to determine whether they support it.  These parsers must
1090      * be able to mark the stream, read enough data to determine whether they
1091      * support the stream, and, if not, reset the stream's read pointer to its original
1092      * position.  If the input stream does not support these operation, this method may fail
1093      * with an <code>IOException</code>.
1094      * @param stream the input stream from which the <code>AudioInputStream</code> should be
1095      * constructed
1096      * @return an <code>AudioInputStream</code> object based on the audio file data contained
1097      * in the input stream.
1098      * @throws UnsupportedAudioFileException if the stream does not point to valid audio
1099      * file data recognized by the system
1100      * @throws IOException if an I/O exception occurs
1101      * @see InputStream#markSupported
1102      * @see InputStream#mark
1103      */
1104     public static AudioInputStream getAudioInputStream(InputStream stream)
1105         throws UnsupportedAudioFileException, IOException {
1106 
1107         List providers = getAudioFileReaders();
1108         AudioInputStream audioStream = null;
1109 
1110         for(int i = 0; i < providers.size(); i++ ) {
1111             AudioFileReader reader = (AudioFileReader) providers.get(i);
1112             try {
1113                 audioStream = reader.getAudioInputStream( stream ); // throws IOException
1114                 break;
1115             } catch (UnsupportedAudioFileException e) {
1116                 continue;
1117             }
1118         }
1119 
1120         if( audioStream==null ) {
1121             throw new UnsupportedAudioFileException("could not get audio input stream from input stream");
1122         } else {
1123             return audioStream;
1124         }
1125     }
1126 
1127     /**
1128      * Obtains an audio input stream from the URL provided.  The URL must
1129      * point to valid audio file data.
1130      * @param url the URL for which the <code>AudioInputStream</code> should be
1131      * constructed
1132      * @return an <code>AudioInputStream</code> object based on the audio file data pointed
1133      * to by the URL
1134      * @throws UnsupportedAudioFileException if the URL does not point to valid audio
1135      * file data recognized by the system
1136      * @throws IOException if an I/O exception occurs
1137      */
1138     public static AudioInputStream getAudioInputStream(URL url)
1139         throws UnsupportedAudioFileException, IOException {
1140 
1141         List providers = getAudioFileReaders();
1142         AudioInputStream audioStream = null;
1143 
1144         for(int i = 0; i < providers.size(); i++ ) {
1145             AudioFileReader reader = (AudioFileReader) providers.get(i);
1146             try {
1147                 audioStream = reader.getAudioInputStream( url ); // throws IOException
1148                 break;
1149             } catch (UnsupportedAudioFileException e) {
1150                 continue;
1151             }
1152         }
1153 
1154         if( audioStream==null ) {
1155             throw new UnsupportedAudioFileException("could not get audio input stream from input URL");
1156         } else {
1157             return audioStream;
1158         }
1159     }
1160 
1161     /**
1162      * Obtains an audio input stream from the provided <code>File</code>.  The <code>File</code> must
1163      * point to valid audio file data.
1164      * @param file the <code>File</code> for which the <code>AudioInputStream</code> should be
1165      * constructed
1166      * @return an <code>AudioInputStream</code> object based on the audio file data pointed
1167      * to by the <code>File</code>
1168      * @throws UnsupportedAudioFileException if the <code>File</code> does not point to valid audio
1169      * file data recognized by the system
1170      * @throws IOException if an I/O exception occurs
1171      */
1172     public static AudioInputStream getAudioInputStream(File file)
1173         throws UnsupportedAudioFileException, IOException {
1174 
1175         List providers = getAudioFileReaders();
1176         AudioInputStream audioStream = null;
1177 
1178         for(int i = 0; i < providers.size(); i++ ) {
1179             AudioFileReader reader = (AudioFileReader) providers.get(i);
1180             try {
1181                 audioStream = reader.getAudioInputStream( file ); // throws IOException
1182                 break;
1183             } catch (UnsupportedAudioFileException e) {
1184                 continue;
1185             }
1186         }
1187 
1188         if( audioStream==null ) {
1189             throw new UnsupportedAudioFileException("could not get audio input stream from input file");
1190         } else {
1191             return audioStream;
1192         }
1193     }
1194 
1195 
1196     /**
1197      * Obtains the file types for which file writing support is provided by the system.
1198      * @return array of unique file types.  If no file types are supported,
1199      * an array of length 0 is returned.
1200      */
1201     public static AudioFileFormat.Type[] getAudioFileTypes() {
1202         List providers = getAudioFileWriters();
1203         Set returnTypesSet = new HashSet();
1204 
1205         for(int i=0; i < providers.size(); i++) {
1206             AudioFileWriter writer = (AudioFileWriter) providers.get(i);
1207             AudioFileFormat.Type[] fileTypes = writer.getAudioFileTypes();
1208             for(int j=0; j < fileTypes.length; j++) {
1209                 returnTypesSet.add(fileTypes[j]);
1210             }
1211         }
1212         AudioFileFormat.Type returnTypes[] = (AudioFileFormat.Type[])
1213             returnTypesSet.toArray(new AudioFileFormat.Type[0]);
1214         return returnTypes;
1215     }
1216 
1217 
1218     /**
1219      * Indicates whether file writing support for the specified file type is provided
1220      * by the system.
1221      * @param fileType the file type for which write capabilities are queried
1222      * @return <code>true</code> if the file type is supported,
1223      * otherwise <code>false</code>
1224      */
1225     public static boolean isFileTypeSupported(AudioFileFormat.Type fileType) {
1226 
1227         List providers = getAudioFileWriters();
1228 
1229         for(int i=0; i < providers.size(); i++) {
1230             AudioFileWriter writer = (AudioFileWriter) providers.get(i);
1231             if (writer.isFileTypeSupported(fileType)) {
1232                 return true;
1233             }
1234         }
1235         return false;
1236     }
1237 
1238 
1239     /**
1240      * Obtains the file types that the system can write from the
1241      * audio input stream specified.
1242      * @param stream the audio input stream for which audio file type support
1243      * is queried
1244      * @return array of file types.  If no file types are supported,
1245      * an array of length 0 is returned.
1246      */
1247     public static AudioFileFormat.Type[] getAudioFileTypes(AudioInputStream stream) {
1248         List providers = getAudioFileWriters();
1249         Set returnTypesSet = new HashSet();
1250 
1251         for(int i=0; i < providers.size(); i++) {
1252             AudioFileWriter writer = (AudioFileWriter) providers.get(i);
1253             AudioFileFormat.Type[] fileTypes = writer.getAudioFileTypes(stream);
1254             for(int j=0; j < fileTypes.length; j++) {
1255                 returnTypesSet.add(fileTypes[j]);
1256             }
1257         }
1258         AudioFileFormat.Type returnTypes[] = (AudioFileFormat.Type[])
1259             returnTypesSet.toArray(new AudioFileFormat.Type[0]);
1260         return returnTypes;
1261     }
1262 
1263 
1264     /**
1265      * Indicates whether an audio file of the specified file type can be written
1266      * from the indicated audio input stream.
1267      * @param fileType the file type for which write capabilities are queried
1268      * @param stream the stream for which file-writing support is queried
1269      * @return <code>true</code> if the file type is supported for this audio input stream,
1270      * otherwise <code>false</code>
1271      */
1272     public static boolean isFileTypeSupported(AudioFileFormat.Type fileType,
1273                                               AudioInputStream stream) {
1274 
1275         List providers = getAudioFileWriters();
1276 
1277         for(int i=0; i < providers.size(); i++) {
1278             AudioFileWriter writer = (AudioFileWriter) providers.get(i);
1279             if(writer.isFileTypeSupported(fileType, stream)) {
1280                 return true;
1281             }
1282         }
1283         return false;
1284     }
1285 
1286 
1287     /**
1288      * Writes a stream of bytes representing an audio file of the specified file type
1289      * to the output stream provided.  Some file types require that
1290      * the length be written into the file header; such files cannot be written from
1291      * start to finish unless the length is known in advance.  An attempt
1292      * to write a file of such a type will fail with an IOException if the length in
1293      * the audio file type is <code>AudioSystem.NOT_SPECIFIED</code>.
1294      *
1295      * @param stream the audio input stream containing audio data to be
1296      * written to the file
1297      * @param fileType the kind of audio file to write
1298      * @param out the stream to which the file data should be written
1299      * @return the number of bytes written to the output stream
1300      * @throws IOException if an input/output exception occurs
1301      * @throws IllegalArgumentException if the file type is not supported by
1302      * the system
1303      * @see #isFileTypeSupported
1304      * @see     #getAudioFileTypes
1305      */
1306     public static int write(AudioInputStream stream, AudioFileFormat.Type fileType,
1307                             OutputStream out) throws IOException {
1308 
1309         List providers = getAudioFileWriters();
1310         int bytesWritten = 0;
1311         boolean flag = false;
1312 
1313         for(int i=0; i < providers.size(); i++) {
1314             AudioFileWriter writer = (AudioFileWriter) providers.get(i);
1315             try {
1316                 bytesWritten = writer.write( stream, fileType, out ); // throws IOException
1317                 flag = true;
1318                 break;
1319             } catch (IllegalArgumentException e) {
1320                 // thrown if this provider cannot write the sequence, try the next
1321                 continue;
1322             }
1323         }
1324         if(!flag) {
1325             throw new IllegalArgumentException("could not write audio file: file type not supported: " + fileType);
1326         } else {
1327             return bytesWritten;
1328         }
1329     }
1330 
1331 
1332     /**
1333      * Writes a stream of bytes representing an audio file of the specified file type
1334      * to the external file provided.
1335      * @param stream the audio input stream containing audio data to be
1336      * written to the file
1337      * @param fileType the kind of audio file to write
1338      * @param out the external file to which the file data should be written
1339      * @return the number of bytes written to the file
1340      * @throws IOException if an I/O exception occurs
1341      * @throws IllegalArgumentException if the file type is not supported by
1342      * the system
1343      * @see #isFileTypeSupported
1344      * @see     #getAudioFileTypes
1345      */
1346     public static int write(AudioInputStream stream, AudioFileFormat.Type fileType,
1347                             File out) throws IOException {
1348 
1349         List providers = getAudioFileWriters();
1350         int bytesWritten = 0;
1351         boolean flag = false;
1352 
1353         for(int i=0; i < providers.size(); i++) {
1354             AudioFileWriter writer = (AudioFileWriter) providers.get(i);
1355             try {
1356                 bytesWritten = writer.write( stream, fileType, out ); // throws IOException
1357                 flag = true;
1358                 break;
1359             } catch (IllegalArgumentException e) {
1360                 // thrown if this provider cannot write the sequence, try the next
1361                 continue;
1362             }
1363         }
1364         if (!flag) {
1365             throw new IllegalArgumentException("could not write audio file: file type not supported: " + fileType);
1366         } else {
1367             return bytesWritten;
1368         }
1369     }
1370 
1371 
1372     // METHODS FOR INTERNAL IMPLEMENTATION USE
1373 
1374     /**
1375      * Obtains the set of MixerProviders on the system.
1376      */
1377     private static List getMixerProviders() {
1378         return getProviders(MixerProvider.class);

1379     }
1380 
1381 
1382     /**
1383      * Obtains the set of format converters (codecs, transcoders, etc.)
1384      * that are currently installed on the system.
1385      * @return an array of
1386      * {@link javax.sound.sampled.spi.FormatConversionProvider
1387      * FormatConversionProvider}
1388      * objects representing the available format converters.  If no format
1389      * converters readers are available on the system, an array of length 0 is
1390      * returned.
1391      */
1392     private static List getFormatConversionProviders() {
1393         return getProviders(FormatConversionProvider.class);

1394     }
1395 
1396 
1397     /**
1398      * Obtains the set of audio file readers that are currently installed on the system.
1399      * @return a List of
1400      * {@link javax.sound.sampled.spi.AudioFileReader
1401      * AudioFileReader}
1402      * objects representing the installed audio file readers.  If no audio file
1403      * readers are available on the system, an empty List is returned.
1404      */
1405     private static List getAudioFileReaders() {
1406         return getProviders(AudioFileReader.class);

1407     }
1408 
1409 
1410     /**
1411      * Obtains the set of audio file writers that are currently installed on the system.
1412      * @return a List of
1413      * {@link javax.sound.samples.spi.AudioFileWriter AudioFileWriter}
1414      * objects representing the available audio file writers.  If no audio file
1415      * writers are available on the system, an empty List is returned.
1416      */
1417     private static List getAudioFileWriters() {
1418         return getProviders(AudioFileWriter.class);

1419     }
1420 
1421 
1422 
1423     /** Attempts to locate and return a default Mixer that provides lines
1424      * of the specified type.
1425      *
1426      * @param providers the installed mixer providers
1427      * @param info The requested line type
1428      * TargetDataLine.class, Clip.class or Port.class.
1429      * @return a Mixer that matches the requirements, or null if no default mixer found
1430      */
1431     private static Mixer getDefaultMixer(List providers, Line.Info info) {
1432         Class lineClass = info.getLineClass();
1433         String providerClassName = JDK13Services.getDefaultProviderClassName(lineClass);
1434         String instanceName = JDK13Services.getDefaultInstanceName(lineClass);
1435         Mixer mixer;
1436 
1437         if (providerClassName != null) {
1438             MixerProvider defaultProvider = getNamedProvider(providerClassName, providers);
1439             if (defaultProvider != null) {
1440                 if (instanceName != null) {
1441                     mixer = getNamedMixer(instanceName, defaultProvider, info);
1442                     if (mixer != null) {
1443                         return mixer;
1444                     }
1445                 } else {
1446                     mixer = getFirstMixer(defaultProvider, info,
1447                                           false /* mixing not required*/);
1448                     if (mixer != null) {
1449                         return mixer;
1450                     }
1451                 }
1452 


1464         }
1465 
1466 
1467         /* No default are specified, or if something is specified, everything
1468            failed. */
1469         return null;
1470     }
1471 
1472 
1473 
1474     /** Return a MixerProvider of a given class from the list of
1475         MixerProviders.
1476 
1477         This method never requires the returned Mixer to do mixing.
1478         @param providerClassName The class name of the provider to be returned.
1479         @param providers The list of MixerProviders that is searched.
1480         @return A MixerProvider of the requested class, or null if none is
1481         found.
1482      */
1483     private static MixerProvider getNamedProvider(String providerClassName,
1484                                                   List providers) {
1485         for(int i = 0; i < providers.size(); i++) {
1486             MixerProvider provider = (MixerProvider) providers.get(i);
1487             if (provider.getClass().getName().equals(providerClassName)) {
1488                 return provider;
1489             }
1490         }
1491         return null;
1492     }
1493 
1494 
1495     /** Return a Mixer with a given name from a given MixerProvider.
1496       This method never requires the returned Mixer to do mixing.
1497       @param mixerName The name of the Mixer to be returned.
1498       @param provider The MixerProvider to check for Mixers.
1499       @param info The type of line the returned Mixer is required to
1500       support.
1501 
1502       @return A Mixer matching the requirements, or null if none is found.
1503      */
1504     private static Mixer getNamedMixer(String mixerName,
1505                                        MixerProvider provider,
1506                                        Line.Info info) {


1509             if (infos[i].getName().equals(mixerName)) {
1510                 Mixer mixer = provider.getMixer(infos[i]);
1511                 if (isAppropriateMixer(mixer, info, false)) {
1512                     return mixer;
1513                 }
1514             }
1515         }
1516         return null;
1517     }
1518 
1519 
1520     /** From a List of MixerProviders, return a Mixer with a given name.
1521         This method never requires the returned Mixer to do mixing.
1522         @param mixerName The name of the Mixer to be returned.
1523         @param providers The List of MixerProviders to check for Mixers.
1524         @param info The type of line the returned Mixer is required to
1525         support.
1526         @return A Mixer matching the requirements, or null if none is found.
1527      */
1528     private static Mixer getNamedMixer(String mixerName,
1529                                        List providers,
1530                                        Line.Info info) {
1531         for(int i = 0; i < providers.size(); i++) {
1532             MixerProvider provider = (MixerProvider) providers.get(i);
1533             Mixer mixer = getNamedMixer(mixerName, provider, info);
1534             if (mixer != null) {
1535                 return mixer;
1536             }
1537         }
1538         return null;
1539     }
1540 
1541 
1542     /** From a given MixerProvider, return the first appropriate Mixer.
1543         @param provider The MixerProvider to check for Mixers.
1544         @param info The type of line the returned Mixer is required to
1545         support.
1546         @param isMixingRequired If true, only Mixers that support mixing are
1547         returned for line types of SourceDataLine and Clip.
1548 
1549         @return A Mixer that is considered appropriate, or null
1550         if none is found.
1551      */
1552     private static Mixer getFirstMixer(MixerProvider provider,


1561         }
1562         return null;
1563     }
1564 
1565 
1566     /** Checks if a Mixer is appropriate.
1567         A Mixer is considered appropriate if it support the given line type.
1568         If isMixingRequired is true and the line type is an output one
1569         (SourceDataLine, Clip), the mixer is appropriate if it supports
1570         at least 2 (concurrent) lines of the given type.
1571 
1572         @return true if the mixer is considered appropriate according to the
1573         rules given above, false otherwise.
1574      */
1575     private static boolean isAppropriateMixer(Mixer mixer,
1576                                               Line.Info lineInfo,
1577                                               boolean isMixingRequired) {
1578         if (! mixer.isLineSupported(lineInfo)) {
1579             return false;
1580         }
1581         Class lineClass = lineInfo.getLineClass();
1582         if (isMixingRequired
1583             && (SourceDataLine.class.isAssignableFrom(lineClass) ||
1584                 Clip.class.isAssignableFrom(lineClass))) {
1585             int maxLines = mixer.getMaxLines(lineInfo);
1586             return ((maxLines == NOT_SPECIFIED) || (maxLines > 1));
1587         }
1588         return true;
1589     }
1590 
1591 
1592 
1593     /**
1594      * Like getMixerInfo, but return List
1595      */
1596     private static List getMixerInfoList() {
1597         List providers = getMixerProviders();
1598         return getMixerInfoList(providers);
1599     }
1600 
1601 
1602     /**
1603      * Like getMixerInfo, but return List
1604      */
1605     private static List getMixerInfoList(List providers) {
1606         List infos = new ArrayList();
1607 
1608         Mixer.Info[] someInfos; // per-mixer
1609         Mixer.Info[] allInfos;  // for all mixers
1610 
1611         for(int i = 0; i < providers.size(); i++ ) {
1612             someInfos = ((MixerProvider)providers.get(i)).getMixerInfo();
1613 
1614             for (int j = 0; j < someInfos.length; j++) {
1615                 infos.add(someInfos[j]);
1616             }
1617         }
1618 
1619         return infos;
1620     }
1621 
1622 
1623     /**
1624      * Obtains the set of services currently installed on the system
1625      * using 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      */
1629     private static List getProviders(Class providerClass) {
1630         return JDK13Services.getProviders(providerClass);
1631     }
1632 }


 179      * methods may also accept or return this value, as documented.
 180      */
 181     public static final int NOT_SPECIFIED = -1;
 182 
 183     /**
 184      * Private no-args constructor for ensuring against instantiation.
 185      */
 186     private AudioSystem() {
 187     }
 188 
 189 
 190     /**
 191      * Obtains an array of mixer info objects that represents
 192      * the set of audio mixers that are currently installed on the system.
 193      * @return an array of info objects for the currently installed mixers.  If no mixers
 194      * are available on the system, an array of length 0 is returned.
 195      * @see #getMixer
 196      */
 197     public static Mixer.Info[] getMixerInfo() {
 198 
 199         List<Mixer.Info> infos = getMixerInfoList();
 200         Mixer.Info[] allInfos = infos.toArray(new Mixer.Info[infos.size()]);
 201         return allInfos;
 202     }
 203 
 204 
 205     /**
 206      * Obtains the requested audio mixer.
 207      * @param info a <code>Mixer.Info</code> object representing the desired
 208      * mixer, or <code>null</code> for the system default mixer
 209      * @return the requested mixer
 210      * @throws SecurityException if the requested mixer
 211      * is unavailable because of security restrictions
 212      * @throws IllegalArgumentException if the info object does not represent
 213      * a mixer installed on the system
 214      * @see #getMixerInfo
 215      */
 216     public static Mixer getMixer(Mixer.Info info) {
 217 
 218         Mixer mixer = null;
 219         List<MixerProvider> providers = getMixerProviders();
 220 
 221         for(int i = 0; i < providers.size(); i++ ) {
 222 
 223             try {
 224                 return providers.get(i).getMixer(info);
 225 
 226             } catch (IllegalArgumentException e) {
 227             } catch (NullPointerException e) {
 228                 // $$jb 08.20.99:  If the strings in the info object aren't
 229                 // set, then Netscape (using jdk1.1.5) tends to throw
 230                 // NPE's when doing some string manipulation.  This is
 231                 // probably not the best fix, but is solves the problem
 232                 // of the NPE in Netscape using local classes
 233                 // $$jb 11.01.99: Replacing this patch.
 234             }
 235         }
 236 
 237         //$$fb if looking for default mixer, and not found yet, add a round of looking
 238         if (info == null) {
 239             for(int i = 0; i < providers.size(); i++ ) {
 240                 try {
 241                     MixerProvider provider = providers.get(i);
 242                     Mixer.Info[] infos = provider.getMixerInfo();
 243                     // start from 0 to last device (do not reverse this order)
 244                     for (int ii = 0; ii < infos.length; ii++) {
 245                         try {
 246                             return provider.getMixer(infos[ii]);
 247                         } catch (IllegalArgumentException e) {
 248                             // this is not a good default device :)
 249                         }
 250                     }
 251                 } catch (IllegalArgumentException e) {
 252                 } catch (NullPointerException e) {
 253                 }
 254             }
 255         }
 256 
 257 
 258         throw new IllegalArgumentException("Mixer not supported: "
 259                                            + (info!=null?info.toString():"null"));
 260     }
 261 
 262 
 263     //$$fb 2002-11-26: fix for 4757930: DOC: AudioSystem.getTarget/SourceLineInfo() is ambiguous
 264     /**
 265      * Obtains information about all source lines of a particular type that are supported
 266      * by the installed mixers.
 267      * @param info a <code>Line.Info</code> object that specifies the kind of
 268      * lines about which information is requested
 269      * @return an array of <code>Line.Info</code> objects describing source lines matching
 270      * the type requested.  If no matching source lines are supported, an array of length 0
 271      * is returned.
 272      *
 273      * @see Mixer#getSourceLineInfo(Line.Info)
 274      */
 275     public static Line.Info[] getSourceLineInfo(Line.Info info) {
 276 
 277         Vector<Line.Info> vector = new Vector<>();
 278         Line.Info[] currentInfoArray;
 279 
 280         Mixer mixer;
 281         Line.Info fullInfo = null;
 282         Mixer.Info[] infoArray = getMixerInfo();
 283 
 284         for (int i = 0; i < infoArray.length; i++) {
 285 
 286             mixer = getMixer(infoArray[i]);
 287 
 288             currentInfoArray = mixer.getSourceLineInfo(info);
 289             for (int j = 0; j < currentInfoArray.length; j++) {
 290                 vector.addElement(currentInfoArray[j]);
 291             }
 292         }
 293 
 294         Line.Info[] returnedArray = new Line.Info[vector.size()];
 295 
 296         for (int i = 0; i < returnedArray.length; i++) {
 297             returnedArray[i] = vector.get(i);
 298         }
 299 
 300         return returnedArray;
 301     }
 302 
 303 
 304     /**
 305      * Obtains information about all target lines of a particular type that are supported
 306      * by the installed mixers.
 307      * @param info a <code>Line.Info</code> object that specifies the kind of
 308      * lines about which information is requested
 309      * @return an array of <code>Line.Info</code> objects describing target lines matching
 310      * the type requested.  If no matching target lines are supported, an array of length 0
 311      * is returned.
 312      *
 313      * @see Mixer#getTargetLineInfo(Line.Info)
 314      */
 315     public static Line.Info[] getTargetLineInfo(Line.Info info) {
 316 
 317         Vector<Line.Info> vector = new Vector<>();
 318         Line.Info[] currentInfoArray;
 319 
 320         Mixer mixer;
 321         Line.Info fullInfo = null;
 322         Mixer.Info[] infoArray = getMixerInfo();
 323 
 324         for (int i = 0; i < infoArray.length; i++) {
 325 
 326             mixer = getMixer(infoArray[i]);
 327 
 328             currentInfoArray = mixer.getTargetLineInfo(info);
 329             for (int j = 0; j < currentInfoArray.length; j++) {
 330                 vector.addElement(currentInfoArray[j]);
 331             }
 332         }
 333 
 334         Line.Info[] returnedArray = new Line.Info[vector.size()];
 335 
 336         for (int i = 0; i < returnedArray.length; i++) {
 337             returnedArray[i] = vector.get(i);
 338         }
 339 
 340         return returnedArray;
 341     }
 342 
 343 
 344     /**
 345      * Indicates whether the system supports any lines that match
 346      * the specified <code>Line.Info</code> object.  A line is supported if
 347      * any installed mixer supports it.
 348      * @param info a <code>Line.Info</code> object describing the line for which support is queried
 349      * @return <code>true</code> if at least one matching line is
 350      * supported, otherwise <code>false</code>
 351      *
 352      * @see Mixer#isLineSupported(Line.Info)
 353      */
 354     public static boolean isLineSupported(Line.Info info) {
 355 
 356         Mixer mixer;
 357         Mixer.Info[] infoArray = getMixerInfo();


 391      * If the respective property is not set, or the mixer
 392      * requested in the property is not installed or does not provide the
 393      * requested line, all installed mixers are queried for the
 394      * requested line type. A Line will be returned from the first mixer
 395      * providing the requested line type.
 396      *
 397      * @param info a <code>Line.Info</code> object describing the desired kind of line
 398      * @return a line of the requested kind
 399      *
 400      * @throws LineUnavailableException if a matching line
 401      * is not available due to resource restrictions
 402      * @throws SecurityException if a matching line
 403      * is not available due to security restrictions
 404      * @throws IllegalArgumentException if the system does not
 405      * support at least one line matching the specified
 406      * <code>Line.Info</code> object
 407      * through any installed mixer
 408      */
 409     public static Line getLine(Line.Info info) throws LineUnavailableException {
 410         LineUnavailableException lue = null;
 411         List<MixerProvider> providers = getMixerProviders();
 412 
 413 
 414         // 1: try from default mixer for this line class
 415         try {
 416             Mixer mixer = getDefaultMixer(providers, info);
 417             if (mixer != null && mixer.isLineSupported(info)) {
 418                 return mixer.getLine(info);
 419             }
 420         } catch (LineUnavailableException e) {
 421             lue = e;
 422         } catch (IllegalArgumentException iae) {
 423             // must not happen... but better to catch it here,
 424             // if plug-ins are badly written
 425         }
 426 
 427 
 428         // 2: if that doesn't work, try to find any mixing mixer
 429         for(int i = 0; i < providers.size(); i++) {
 430             MixerProvider provider = providers.get(i);
 431             Mixer.Info[] infos = provider.getMixerInfo();
 432 
 433             for (int j = 0; j < infos.length; j++) {
 434                 try {
 435                     Mixer mixer = provider.getMixer(infos[j]);
 436                     // see if this is an appropriate mixer which can mix
 437                     if (isAppropriateMixer(mixer, info, true)) {
 438                         return mixer.getLine(info);
 439                     }
 440                 } catch (LineUnavailableException e) {
 441                     lue = e;
 442                 } catch (IllegalArgumentException iae) {
 443                     // must not happen... but better to catch it here,
 444                     // if plug-ins are badly written
 445                 }
 446             }
 447         }
 448 
 449 
 450         // 3: if that didn't work, try to find any non-mixing mixer
 451         for(int i = 0; i < providers.size(); i++) {
 452             MixerProvider provider = providers.get(i);
 453             Mixer.Info[] infos = provider.getMixerInfo();
 454             for (int j = 0; j < infos.length; j++) {
 455                 try {
 456                     Mixer mixer = provider.getMixer(infos[j]);
 457                     // see if this is an appropriate mixer which can mix
 458                     if (isAppropriateMixer(mixer, info, false)) {
 459                         return mixer.getLine(info);
 460                     }
 461                 } catch (LineUnavailableException e) {
 462                     lue = e;
 463                 } catch (IllegalArgumentException iae) {
 464                     // must not happen... but better to catch it here,
 465                     // if plug-ins are badly written
 466                 }
 467             }
 468         }
 469 
 470         // if this line was supported but was not available, throw the last
 471         // LineUnavailableException we got (??).
 472         if (lue != null) {


 747 
 748         DataLine.Info info = new DataLine.Info(TargetDataLine.class, format);
 749         Mixer mixer = AudioSystem.getMixer(mixerinfo);
 750         return (TargetDataLine) mixer.getLine(info);
 751     }
 752 
 753 
 754     // $$fb 2002-04-12: fix for 4662082: behavior of AudioSystem.getTargetEncodings() methods doesn't match the spec
 755     /**
 756      * Obtains the encodings that the system can obtain from an
 757      * audio input stream with the specified encoding using the set
 758      * of installed format converters.
 759      * @param sourceEncoding the encoding for which conversion support
 760      * is queried
 761      * @return array of encodings.  If <code>sourceEncoding</code>is not supported,
 762      * an array of length 0 is returned. Otherwise, the array will have a length
 763      * of at least 1, representing <code>sourceEncoding</code> (no conversion).
 764      */
 765     public static AudioFormat.Encoding[] getTargetEncodings(AudioFormat.Encoding sourceEncoding) {
 766 
 767         List<FormatConversionProvider> codecs = getFormatConversionProviders();
 768         Vector<AudioFormat.Encoding> encodings = new Vector<>();
 769 
 770         AudioFormat.Encoding encs[] = null;
 771 
 772         // gather from all the codecs
 773         for(int i=0; i<codecs.size(); i++ ) {
 774             FormatConversionProvider codec = codecs.get(i);
 775             if( codec.isSourceEncodingSupported( sourceEncoding ) ) {
 776                 encs = codec.getTargetEncodings();
 777                 for (int j = 0; j < encs.length; j++) {
 778                     encodings.addElement( encs[j] );
 779                 }
 780             }
 781         }
 782         AudioFormat.Encoding encs2[] = encodings.toArray(new AudioFormat.Encoding[0]);
 783         return encs2;
 784     }
 785 
 786 
 787 
 788     // $$fb 2002-04-12: fix for 4662082: behavior of AudioSystem.getTargetEncodings() methods doesn't match the spec
 789     /**
 790      * Obtains the encodings that the system can obtain from an
 791      * audio input stream with the specified format using the set
 792      * of installed format converters.
 793      * @param sourceFormat the audio format for which conversion
 794      * is queried
 795      * @return array of encodings. If <code>sourceFormat</code>is not supported,
 796      * an array of length 0 is returned. Otherwise, the array will have a length
 797      * of at least 1, representing the encoding of <code>sourceFormat</code> (no conversion).
 798      */
 799     public static AudioFormat.Encoding[] getTargetEncodings(AudioFormat sourceFormat) {
 800 
 801 
 802         List<FormatConversionProvider> codecs = getFormatConversionProviders();
 803         Vector<AudioFormat.Encoding[]> encodings = new Vector<>();
 804 
 805         int size = 0;
 806         int index = 0;
 807         AudioFormat.Encoding encs[] = null;
 808 
 809         // gather from all the codecs
 810 
 811         for(int i=0; i<codecs.size(); i++ ) {
 812             encs = codecs.get(i).getTargetEncodings(sourceFormat);
 813             size += encs.length;
 814             encodings.addElement( encs );
 815         }
 816 
 817         // now build a new array
 818 
 819         AudioFormat.Encoding encs2[] = new AudioFormat.Encoding[size];
 820         for(int i=0; i<encodings.size(); i++ ) {
 821             encs = encodings.get(i);
 822             for(int j=0; j<encs.length; j++ ) {
 823                 encs2[index++] = encs[j];
 824             }
 825         }
 826         return encs2;
 827     }
 828 
 829 
 830     /**
 831      * Indicates whether an audio input stream of the specified encoding
 832      * can be obtained from an audio input stream that has the specified
 833      * format.
 834      * @param targetEncoding the desired encoding after conversion
 835      * @param sourceFormat the audio format before conversion
 836      * @return <code>true</code> if the conversion is supported,
 837      * otherwise <code>false</code>
 838      */
 839     public static boolean isConversionSupported(AudioFormat.Encoding targetEncoding, AudioFormat sourceFormat) {
 840 
 841 
 842         List<FormatConversionProvider> codecs = getFormatConversionProviders();
 843 
 844         for(int i=0; i<codecs.size(); i++ ) {
 845             FormatConversionProvider codec = codecs.get(i);
 846             if(codec.isConversionSupported(targetEncoding,sourceFormat) ) {
 847                 return true;
 848             }
 849         }
 850         return false;
 851     }
 852 
 853 
 854     /**
 855      * Obtains an audio input stream of the indicated encoding, by converting the
 856      * provided audio input stream.
 857      * @param targetEncoding the desired encoding after conversion
 858      * @param sourceStream the stream to be converted
 859      * @return an audio input stream of the indicated encoding
 860      * @throws IllegalArgumentException if the conversion is not supported
 861      * @see #getTargetEncodings(AudioFormat.Encoding)
 862      * @see #getTargetEncodings(AudioFormat)
 863      * @see #isConversionSupported(AudioFormat.Encoding, AudioFormat)
 864      * @see #getAudioInputStream(AudioFormat, AudioInputStream)
 865      */
 866     public static AudioInputStream getAudioInputStream(AudioFormat.Encoding targetEncoding,
 867                                                        AudioInputStream sourceStream) {
 868 
 869         List<FormatConversionProvider> codecs = getFormatConversionProviders();
 870 
 871         for(int i = 0; i < codecs.size(); i++) {
 872             FormatConversionProvider codec = codecs.get(i);
 873             if( codec.isConversionSupported( targetEncoding, sourceStream.getFormat() ) ) {
 874                 return codec.getAudioInputStream( targetEncoding, sourceStream );
 875             }
 876         }
 877         // we ran out of options, throw an exception
 878         throw new IllegalArgumentException("Unsupported conversion: " + targetEncoding + " from " + sourceStream.getFormat());
 879     }
 880 
 881 
 882     /**
 883      * Obtains the formats that have a particular encoding and that the system can
 884      * obtain from a stream of the specified format using the set of
 885      * installed format converters.
 886      * @param targetEncoding the desired encoding after conversion
 887      * @param sourceFormat the audio format before conversion
 888      * @return array of formats.  If no formats of the specified
 889      * encoding are supported, an array of length 0 is returned.
 890      */
 891     public static AudioFormat[] getTargetFormats(AudioFormat.Encoding targetEncoding, AudioFormat sourceFormat) {
 892 
 893         List<FormatConversionProvider> codecs = getFormatConversionProviders();
 894         Vector<AudioFormat[]> formats = new Vector<>();
 895 
 896         int size = 0;
 897         int index = 0;
 898         AudioFormat fmts[] = null;
 899 
 900         // gather from all the codecs
 901 
 902         for(int i=0; i<codecs.size(); i++ ) {
 903             FormatConversionProvider codec = codecs.get(i);
 904             fmts = codec.getTargetFormats(targetEncoding, sourceFormat);
 905             size += fmts.length;
 906             formats.addElement( fmts );
 907         }
 908 
 909         // now build a new array
 910 
 911         AudioFormat fmts2[] = new AudioFormat[size];
 912         for(int i=0; i<formats.size(); i++ ) {
 913             fmts = formats.get(i);
 914             for(int j=0; j<fmts.length; j++ ) {
 915                 fmts2[index++] = fmts[j];
 916             }
 917         }
 918         return fmts2;
 919     }
 920 
 921 
 922     /**
 923      * Indicates whether an audio input stream of a specified format
 924      * can be obtained from an audio input stream of another specified format.
 925      * @param targetFormat the desired audio format after conversion
 926      * @param sourceFormat the audio format before conversion
 927      * @return <code>true</code> if the conversion is supported,
 928      * otherwise <code>false</code>
 929      */
 930 
 931     public static boolean isConversionSupported(AudioFormat targetFormat, AudioFormat sourceFormat) {
 932 
 933         List<FormatConversionProvider> codecs = getFormatConversionProviders();
 934 
 935         for(int i=0; i<codecs.size(); i++ ) {
 936             FormatConversionProvider codec = codecs.get(i);
 937             if(codec.isConversionSupported(targetFormat, sourceFormat) ) {
 938                 return true;
 939             }
 940         }
 941         return false;
 942     }
 943 
 944 
 945     /**
 946      * Obtains an audio input stream of the indicated format, by converting the
 947      * provided audio input stream.
 948      * @param targetFormat the desired audio format after conversion
 949      * @param sourceStream the stream to be converted
 950      * @return an audio input stream of the indicated format
 951      * @throws IllegalArgumentException if the conversion is not supported
 952      * #see #getTargetEncodings(AudioFormat)
 953      * @see #getTargetFormats(AudioFormat.Encoding, AudioFormat)
 954      * @see #isConversionSupported(AudioFormat, AudioFormat)
 955      * @see #getAudioInputStream(AudioFormat.Encoding, AudioInputStream)
 956      */
 957     public static AudioInputStream getAudioInputStream(AudioFormat targetFormat,
 958                                                        AudioInputStream sourceStream) {
 959 
 960         if (sourceStream.getFormat().matches(targetFormat)) {
 961             return sourceStream;
 962         }
 963 
 964         List<FormatConversionProvider> codecs = getFormatConversionProviders();
 965 
 966         for(int i = 0; i < codecs.size(); i++) {
 967             FormatConversionProvider codec = codecs.get(i);
 968             if(codec.isConversionSupported(targetFormat,sourceStream.getFormat()) ) {
 969                 return codec.getAudioInputStream(targetFormat,sourceStream);
 970             }
 971         }
 972 
 973         // we ran out of options...
 974         throw new IllegalArgumentException("Unsupported conversion: " + targetFormat + " from " + sourceStream.getFormat());
 975     }
 976 
 977 
 978     /**
 979      * Obtains the audio file format of the provided input stream.  The stream must
 980      * point to valid audio file data.  The implementation of this method may require
 981      * multiple parsers to examine the stream to determine whether they support it.
 982      * These parsers must be able to mark the stream, read enough data to determine whether they
 983      * support the stream, and, if not, reset the stream's read pointer to its original
 984      * position.  If the input stream does not support these operations, this method may fail
 985      * with an <code>IOException</code>.
 986      * @param stream the input stream from which file format information should be
 987      * extracted
 988      * @return an <code>AudioFileFormat</code> object describing the stream's audio file format
 989      * @throws UnsupportedAudioFileException if the stream does not point to valid audio
 990      * file data recognized by the system
 991      * @throws IOException if an input/output exception occurs
 992      * @see InputStream#markSupported
 993      * @see InputStream#mark
 994      */
 995     public static AudioFileFormat getAudioFileFormat(InputStream stream)
 996         throws UnsupportedAudioFileException, IOException {
 997 
 998         List<AudioFileReader> providers = getAudioFileReaders();
 999         AudioFileFormat format = null;
1000 
1001         for(int i = 0; i < providers.size(); i++ ) {
1002             AudioFileReader reader = providers.get(i);
1003             try {
1004                 format = reader.getAudioFileFormat( stream ); // throws IOException
1005                 break;
1006             } catch (UnsupportedAudioFileException e) {
1007                 continue;
1008             }
1009         }
1010 
1011         if( format==null ) {
1012             throw new UnsupportedAudioFileException("file is not a supported file type");
1013         } else {
1014             return format;
1015         }
1016     }
1017 
1018     /**
1019      * Obtains the audio file format of the specified URL.  The URL must
1020      * point to valid audio file data.
1021      * @param url the URL from which file format information should be
1022      * extracted
1023      * @return an <code>AudioFileFormat</code> object describing the audio file format
1024      * @throws UnsupportedAudioFileException if the URL does not point to valid audio
1025      * file data recognized by the system
1026      * @throws IOException if an input/output exception occurs
1027      */
1028     public static AudioFileFormat getAudioFileFormat(URL url)
1029         throws UnsupportedAudioFileException, IOException {
1030 
1031         List<AudioFileReader> providers = getAudioFileReaders();
1032         AudioFileFormat format = null;
1033 
1034         for(int i = 0; i < providers.size(); i++ ) {
1035             AudioFileReader reader = providers.get(i);
1036             try {
1037                 format = reader.getAudioFileFormat( url ); // throws IOException
1038                 break;
1039             } catch (UnsupportedAudioFileException e) {
1040                 continue;
1041             }
1042         }
1043 
1044         if( format==null ) {
1045             throw new UnsupportedAudioFileException("file is not a supported file type");
1046         } else {
1047             return format;
1048         }
1049     }
1050 
1051     /**
1052      * Obtains the audio file format of the specified <code>File</code>.  The <code>File</code> must
1053      * point to valid audio file data.
1054      * @param file the <code>File</code> from which file format information should be
1055      * extracted
1056      * @return an <code>AudioFileFormat</code> object describing the audio file format
1057      * @throws UnsupportedAudioFileException if the <code>File</code> does not point to valid audio
1058      * file data recognized by the system
1059      * @throws IOException if an I/O exception occurs
1060      */
1061     public static AudioFileFormat getAudioFileFormat(File file)
1062         throws UnsupportedAudioFileException, IOException {
1063 
1064         List<AudioFileReader> providers = getAudioFileReaders();
1065         AudioFileFormat format = null;
1066 
1067         for(int i = 0; i < providers.size(); i++ ) {
1068             AudioFileReader reader = providers.get(i);
1069             try {
1070                 format = reader.getAudioFileFormat( file ); // throws IOException
1071                 break;
1072             } catch (UnsupportedAudioFileException e) {
1073                 continue;
1074             }
1075         }
1076 
1077         if( format==null ) {
1078             throw new UnsupportedAudioFileException("file is not a supported file type");
1079         } else {
1080             return format;
1081         }
1082     }
1083 
1084 
1085     /**
1086      * Obtains an audio input stream from the provided input stream.  The stream must
1087      * point to valid audio file data.  The implementation of this method may
1088      * require multiple parsers to
1089      * examine the stream to determine whether they support it.  These parsers must
1090      * be able to mark the stream, read enough data to determine whether they
1091      * support the stream, and, if not, reset the stream's read pointer to its original
1092      * position.  If the input stream does not support these operation, this method may fail
1093      * with an <code>IOExcEption</code>.
1094      * @param stream the input stream from which the <code>AudioInputStream</code> should be
1095      * constructed
1096      * @return an <code>AudioInputStream</code> object based on the audio file data contained
1097      * in the input stream.
1098      * @throws UnsupportedAudioFileException if the stream does not point to valid audio
1099      * file data recognized by the system
1100      * @throws IOException if an I/O exception occurs
1101      * @see InputStream#markSupported
1102      * @see InputStream#mark
1103      */
1104     public static AudioInputStream getAudioInputStream(InputStream stream)
1105         throws UnsupportedAudioFileException, IOException {
1106 
1107         List<AudioFileReader> providers = getAudioFileReaders();
1108         AudioInputStream audioStream = null;
1109 
1110         for(int i = 0; i < providers.size(); i++ ) {
1111             AudioFileReader reader = providers.get(i);
1112             try {
1113                 audioStream = reader.getAudioInputStream( stream ); // throws IOException
1114                 break;
1115             } catch (UnsupportedAudioFileException e) {
1116                 continue;
1117             }
1118         }
1119 
1120         if( audioStream==null ) {
1121             throw new UnsupportedAudioFileException("could not get audio input stream from input stream");
1122         } else {
1123             return audioStream;
1124         }
1125     }
1126 
1127     /**
1128      * Obtains an audio input stream from the URL provided.  The URL must
1129      * point to valid audio file data.
1130      * @param url the URL for which the <code>AudioInputStream</code> should be
1131      * constructed
1132      * @return an <code>AudioInputStream</code> object based on the audio file data pointed
1133      * to by the URL
1134      * @throws UnsupportedAudioFileException if the URL does not point to valid audio
1135      * file data recognized by the system
1136      * @throws IOException if an I/O exception occurs
1137      */
1138     public static AudioInputStream getAudioInputStream(URL url)
1139         throws UnsupportedAudioFileException, IOException {
1140 
1141         List<AudioFileReader> providers = getAudioFileReaders();
1142         AudioInputStream audioStream = null;
1143 
1144         for(int i = 0; i < providers.size(); i++ ) {
1145             AudioFileReader reader = providers.get(i);
1146             try {
1147                 audioStream = reader.getAudioInputStream( url ); // throws IOException
1148                 break;
1149             } catch (UnsupportedAudioFileException e) {
1150                 continue;
1151             }
1152         }
1153 
1154         if( audioStream==null ) {
1155             throw new UnsupportedAudioFileException("could not get audio input stream from input URL");
1156         } else {
1157             return audioStream;
1158         }
1159     }
1160 
1161     /**
1162      * Obtains an audio input stream from the provided <code>File</code>.  The <code>File</code> must
1163      * point to valid audio file data.
1164      * @param file the <code>File</code> for which the <code>AudioInputStream</code> should be
1165      * constructed
1166      * @return an <code>AudioInputStream</code> object based on the audio file data pointed
1167      * to by the <code>File</code>
1168      * @throws UnsupportedAudioFileException if the <code>File</code> does not point to valid audio
1169      * file data recognized by the system
1170      * @throws IOException if an I/O exception occurs
1171      */
1172     public static AudioInputStream getAudioInputStream(File file)
1173         throws UnsupportedAudioFileException, IOException {
1174 
1175         List<AudioFileReader> providers = getAudioFileReaders();
1176         AudioInputStream audioStream = null;
1177 
1178         for(int i = 0; i < providers.size(); i++ ) {
1179             AudioFileReader reader = providers.get(i);
1180             try {
1181                 audioStream = reader.getAudioInputStream( file ); // throws IOException
1182                 break;
1183             } catch (UnsupportedAudioFileException e) {
1184                 continue;
1185             }
1186         }
1187 
1188         if( audioStream==null ) {
1189             throw new UnsupportedAudioFileException("could not get audio input stream from input file");
1190         } else {
1191             return audioStream;
1192         }
1193     }
1194 
1195 
1196     /**
1197      * Obtains the file types for which file writing support is provided by the system.
1198      * @return array of unique file types.  If no file types are supported,
1199      * an array of length 0 is returned.
1200      */
1201     public static AudioFileFormat.Type[] getAudioFileTypes() {
1202         List<AudioFileWriter> providers = getAudioFileWriters();
1203         Set<AudioFileFormat.Type> returnTypesSet = new HashSet<>();
1204 
1205         for(int i=0; i < providers.size(); i++) {
1206             AudioFileWriter writer = providers.get(i);
1207             AudioFileFormat.Type[] fileTypes = writer.getAudioFileTypes();
1208             for(int j=0; j < fileTypes.length; j++) {
1209                 returnTypesSet.add(fileTypes[j]);
1210             }
1211         }
1212         AudioFileFormat.Type returnTypes[] =
1213             returnTypesSet.toArray(new AudioFileFormat.Type[0]);
1214         return returnTypes;
1215     }
1216 
1217 
1218     /**
1219      * Indicates whether file writing support for the specified file type is provided
1220      * by the system.
1221      * @param fileType the file type for which write capabilities are queried
1222      * @return <code>true</code> if the file type is supported,
1223      * otherwise <code>false</code>
1224      */
1225     public static boolean isFileTypeSupported(AudioFileFormat.Type fileType) {
1226 
1227         List<AudioFileWriter> providers = getAudioFileWriters();
1228 
1229         for(int i=0; i < providers.size(); i++) {
1230             AudioFileWriter writer = providers.get(i);
1231             if (writer.isFileTypeSupported(fileType)) {
1232                 return true;
1233             }
1234         }
1235         return false;
1236     }
1237 
1238 
1239     /**
1240      * Obtains the file types that the system can write from the
1241      * audio input stream specified.
1242      * @param stream the audio input stream for which audio file type support
1243      * is queried
1244      * @return array of file types.  If no file types are supported,
1245      * an array of length 0 is returned.
1246      */
1247     public static AudioFileFormat.Type[] getAudioFileTypes(AudioInputStream stream) {
1248         List<AudioFileWriter> providers = getAudioFileWriters();
1249         Set<AudioFileFormat.Type> returnTypesSet = new HashSet<>();
1250 
1251         for(int i=0; i < providers.size(); i++) {
1252             AudioFileWriter writer = providers.get(i);
1253             AudioFileFormat.Type[] fileTypes = writer.getAudioFileTypes(stream);
1254             for(int j=0; j < fileTypes.length; j++) {
1255                 returnTypesSet.add(fileTypes[j]);
1256             }
1257         }
1258         AudioFileFormat.Type returnTypes[] =
1259             returnTypesSet.toArray(new AudioFileFormat.Type[0]);
1260         return returnTypes;
1261     }
1262 
1263 
1264     /**
1265      * Indicates whether an audio file of the specified file type can be written
1266      * from the indicated audio input stream.
1267      * @param fileType the file type for which write capabilities are queried
1268      * @param stream the stream for which file-writing support is queried
1269      * @return <code>true</code> if the file type is supported for this audio input stream,
1270      * otherwise <code>false</code>
1271      */
1272     public static boolean isFileTypeSupported(AudioFileFormat.Type fileType,
1273                                               AudioInputStream stream) {
1274 
1275         List<AudioFileWriter> providers = getAudioFileWriters();
1276 
1277         for(int i=0; i < providers.size(); i++) {
1278             AudioFileWriter writer = providers.get(i);
1279             if(writer.isFileTypeSupported(fileType, stream)) {
1280                 return true;
1281             }
1282         }
1283         return false;
1284     }
1285 
1286 
1287     /**
1288      * Writes a stream of bytes representing an audio file of the specified file type
1289      * to the output stream provided.  Some file types require that
1290      * the length be written into the file header; such files cannot be written from
1291      * start to finish unless the length is known in advance.  An attempt
1292      * to write a file of such a type will fail with an IOException if the length in
1293      * the audio file type is <code>AudioSystem.NOT_SPECIFIED</code>.
1294      *
1295      * @param stream the audio input stream containing audio data to be
1296      * written to the file
1297      * @param fileType the kind of audio file to write
1298      * @param out the stream to which the file data should be written
1299      * @return the number of bytes written to the output stream
1300      * @throws IOException if an input/output exception occurs
1301      * @throws IllegalArgumentException if the file type is not supported by
1302      * the system
1303      * @see #isFileTypeSupported
1304      * @see     #getAudioFileTypes
1305      */
1306     public static int write(AudioInputStream stream, AudioFileFormat.Type fileType,
1307                             OutputStream out) throws IOException {
1308 
1309         List<AudioFileWriter> providers = getAudioFileWriters();
1310         int bytesWritten = 0;
1311         boolean flag = false;
1312 
1313         for(int i=0; i < providers.size(); i++) {
1314             AudioFileWriter writer = providers.get(i);
1315             try {
1316                 bytesWritten = writer.write( stream, fileType, out ); // throws IOException
1317                 flag = true;
1318                 break;
1319             } catch (IllegalArgumentException e) {
1320                 // thrown if this provider cannot write the sequence, try the next
1321                 continue;
1322             }
1323         }
1324         if(!flag) {
1325             throw new IllegalArgumentException("could not write audio file: file type not supported: " + fileType);
1326         } else {
1327             return bytesWritten;
1328         }
1329     }
1330 
1331 
1332     /**
1333      * Writes a stream of bytes representing an audio file of the specified file type
1334      * to the external file provided.
1335      * @param stream the audio input stream containing audio data to be
1336      * written to the file
1337      * @param fileType the kind of audio file to write
1338      * @param out the external file to which the file data should be written
1339      * @return the number of bytes written to the file
1340      * @throws IOException if an I/O exception occurs
1341      * @throws IllegalArgumentException if the file type is not supported by
1342      * the system
1343      * @see #isFileTypeSupported
1344      * @see     #getAudioFileTypes
1345      */
1346     public static int write(AudioInputStream stream, AudioFileFormat.Type fileType,
1347                             File out) throws IOException {
1348 
1349         List<AudioFileWriter> providers = getAudioFileWriters();
1350         int bytesWritten = 0;
1351         boolean flag = false;
1352 
1353         for(int i=0; i < providers.size(); i++) {
1354             AudioFileWriter writer = providers.get(i);
1355             try {
1356                 bytesWritten = writer.write( stream, fileType, out ); // throws IOException
1357                 flag = true;
1358                 break;
1359             } catch (IllegalArgumentException e) {
1360                 // thrown if this provider cannot write the sequence, try the next
1361                 continue;
1362             }
1363         }
1364         if (!flag) {
1365             throw new IllegalArgumentException("could not write audio file: file type not supported: " + fileType);
1366         } else {
1367             return bytesWritten;
1368         }
1369     }
1370 
1371 
1372     // METHODS FOR INTERNAL IMPLEMENTATION USE
1373 
1374     /**
1375      * Obtains the set of MixerProviders on the system.
1376      */
1377     @SuppressWarnings("unchecked")
1378     private static List<MixerProvider> getMixerProviders() {
1379         return (List<MixerProvider>) getProviders(MixerProvider.class);
1380     }
1381 
1382 
1383     /**
1384      * Obtains the set of format converters (codecs, transcoders, etc.)
1385      * that are currently installed on the system.
1386      * @return an array of
1387      * {@link javax.sound.sampled.spi.FormatConversionProvider
1388      * FormatConversionProvider}
1389      * objects representing the available format converters.  If no format
1390      * converters readers are available on the system, an array of length 0 is
1391      * returned.
1392      */
1393     @SuppressWarnings("unchecked")
1394     private static List<FormatConversionProvider> getFormatConversionProviders() {
1395         return (List<FormatConversionProvider>) getProviders(FormatConversionProvider.class);
1396     }
1397 
1398 
1399     /**
1400      * Obtains the set of audio file readers that are currently installed on the system.
1401      * @return a List of
1402      * {@link javax.sound.sampled.spi.AudioFileReader
1403      * AudioFileReader}
1404      * objects representing the installed audio file readers.  If no audio file
1405      * readers are available on the system, an empty List is returned.
1406      */
1407     @SuppressWarnings("unchecked")
1408     private static List<AudioFileReader> getAudioFileReaders() {
1409         return (List<AudioFileReader>)getProviders(AudioFileReader.class);
1410     }
1411 
1412 
1413     /**
1414      * Obtains the set of audio file writers that are currently installed on the system.
1415      * @return a List of
1416      * {@link javax.sound.samples.spi.AudioFileWriter AudioFileWriter}
1417      * objects representing the available audio file writers.  If no audio file
1418      * writers are available on the system, an empty List is returned.
1419      */
1420     @SuppressWarnings("unchecked")
1421     private static List<AudioFileWriter> getAudioFileWriters() {
1422         return (List<AudioFileWriter>)getProviders(AudioFileWriter.class);
1423     }
1424 
1425 
1426 
1427     /** Attempts to locate and return a default Mixer that provides lines
1428      * of the specified type.
1429      *
1430      * @param providers the installed mixer providers
1431      * @param info The requested line type
1432      * TargetDataLine.class, Clip.class or Port.class.
1433      * @return a Mixer that matches the requirements, or null if no default mixer found
1434      */
1435     private static Mixer getDefaultMixer(List<MixerProvider> providers, Line.Info info) {
1436         Class<?> lineClass = info.getLineClass();
1437         String providerClassName = JDK13Services.getDefaultProviderClassName(lineClass);
1438         String instanceName = JDK13Services.getDefaultInstanceName(lineClass);
1439         Mixer mixer;
1440 
1441         if (providerClassName != null) {
1442             MixerProvider defaultProvider = getNamedProvider(providerClassName, providers);
1443             if (defaultProvider != null) {
1444                 if (instanceName != null) {
1445                     mixer = getNamedMixer(instanceName, defaultProvider, info);
1446                     if (mixer != null) {
1447                         return mixer;
1448                     }
1449                 } else {
1450                     mixer = getFirstMixer(defaultProvider, info,
1451                                           false /* mixing not required*/);
1452                     if (mixer != null) {
1453                         return mixer;
1454                     }
1455                 }
1456 


1468         }
1469 
1470 
1471         /* No default are specified, or if something is specified, everything
1472            failed. */
1473         return null;
1474     }
1475 
1476 
1477 
1478     /** Return a MixerProvider of a given class from the list of
1479         MixerProviders.
1480 
1481         This method never requires the returned Mixer to do mixing.
1482         @param providerClassName The class name of the provider to be returned.
1483         @param providers The list of MixerProviders that is searched.
1484         @return A MixerProvider of the requested class, or null if none is
1485         found.
1486      */
1487     private static MixerProvider getNamedProvider(String providerClassName,
1488                                                   List<MixerProvider> providers) {
1489         for(int i = 0; i < providers.size(); i++) {
1490             MixerProvider provider = providers.get(i);
1491             if (provider.getClass().getName().equals(providerClassName)) {
1492                 return provider;
1493             }
1494         }
1495         return null;
1496     }
1497 
1498 
1499     /** Return a Mixer with a given name from a given MixerProvider.
1500       This method never requires the returned Mixer to do mixing.
1501       @param mixerName The name of the Mixer to be returned.
1502       @param provider The MixerProvider to check for Mixers.
1503       @param info The type of line the returned Mixer is required to
1504       support.
1505 
1506       @return A Mixer matching the requirements, or null if none is found.
1507      */
1508     private static Mixer getNamedMixer(String mixerName,
1509                                        MixerProvider provider,
1510                                        Line.Info info) {


1513             if (infos[i].getName().equals(mixerName)) {
1514                 Mixer mixer = provider.getMixer(infos[i]);
1515                 if (isAppropriateMixer(mixer, info, false)) {
1516                     return mixer;
1517                 }
1518             }
1519         }
1520         return null;
1521     }
1522 
1523 
1524     /** From a List of MixerProviders, return a Mixer with a given name.
1525         This method never requires the returned Mixer to do mixing.
1526         @param mixerName The name of the Mixer to be returned.
1527         @param providers The List of MixerProviders to check for Mixers.
1528         @param info The type of line the returned Mixer is required to
1529         support.
1530         @return A Mixer matching the requirements, or null if none is found.
1531      */
1532     private static Mixer getNamedMixer(String mixerName,
1533                                        List<MixerProvider> providers,
1534                                        Line.Info info) {
1535         for(int i = 0; i < providers.size(); i++) {
1536             MixerProvider provider = providers.get(i);
1537             Mixer mixer = getNamedMixer(mixerName, provider, info);
1538             if (mixer != null) {
1539                 return mixer;
1540             }
1541         }
1542         return null;
1543     }
1544 
1545 
1546     /** From a given MixerProvider, return the first appropriate Mixer.
1547         @param provider The MixerProvider to check for Mixers.
1548         @param info The type of line the returned Mixer is required to
1549         support.
1550         @param isMixingRequired If true, only Mixers that support mixing are
1551         returned for line types of SourceDataLine and Clip.
1552 
1553         @return A Mixer that is considered appropriate, or null
1554         if none is found.
1555      */
1556     private static Mixer getFirstMixer(MixerProvider provider,


1565         }
1566         return null;
1567     }
1568 
1569 
1570     /** Checks if a Mixer is appropriate.
1571         A Mixer is considered appropriate if it support the given line type.
1572         If isMixingRequired is true and the line type is an output one
1573         (SourceDataLine, Clip), the mixer is appropriate if it supports
1574         at least 2 (concurrent) lines of the given type.
1575 
1576         @return true if the mixer is considered appropriate according to the
1577         rules given above, false otherwise.
1578      */
1579     private static boolean isAppropriateMixer(Mixer mixer,
1580                                               Line.Info lineInfo,
1581                                               boolean isMixingRequired) {
1582         if (! mixer.isLineSupported(lineInfo)) {
1583             return false;
1584         }
1585         Class<?> lineClass = lineInfo.getLineClass();
1586         if (isMixingRequired
1587             && (SourceDataLine.class.isAssignableFrom(lineClass) ||
1588                 Clip.class.isAssignableFrom(lineClass))) {
1589             int maxLines = mixer.getMaxLines(lineInfo);
1590             return ((maxLines == NOT_SPECIFIED) || (maxLines > 1));
1591         }
1592         return true;
1593     }
1594 
1595 
1596 
1597     /**
1598      * Like getMixerInfo, but return List
1599      */
1600     private static List<Mixer.Info> getMixerInfoList() {
1601         List<MixerProvider> providers = getMixerProviders();
1602         return getMixerInfoList(providers);
1603     }
1604 
1605 
1606     /**
1607      * Like getMixerInfo, but return List
1608      */
1609     private static List<Mixer.Info> getMixerInfoList(List<MixerProvider> providers) {
1610         List<Mixer.Info> infos = new ArrayList<>();
1611 
1612         Mixer.Info[] someInfos; // per-mixer
1613         Mixer.Info[] allInfos;  // for all mixers
1614 
1615         for(int i = 0; i < providers.size(); i++ ) {
1616             someInfos = providers.get(i).getMixerInfo();
1617 
1618             for (int j = 0; j < someInfos.length; j++) {
1619                 infos.add(someInfos[j]);
1620             }
1621         }
1622 
1623         return infos;
1624     }
1625 
1626 
1627     /**
1628      * Obtains the set of services currently installed on the system
1629      * using the SPI mechanism in 1.3.
1630      * @return a List of instances of providers for the requested service.
1631      * If no providers are available, a vector of length 0 will be returned.
1632      */
1633     private static List<?> getProviders(Class<?> providerClass) {
1634         return JDK13Services.getProviders(providerClass);
1635     }
1636 }