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 } |