001/* Main interface to audio system 002 Copyright (C) 2005, 2012 Free Software Foundation, Inc. 003 004This file is part of GNU Classpath. 005 006GNU Classpath is free software; you can redistribute it and/or modify 007it under the terms of the GNU General Public License as published by 008the Free Software Foundation; either version 2, or (at your option) 009any later version. 010 011GNU Classpath is distributed in the hope that it will be useful, but 012WITHOUT ANY WARRANTY; without even the implied warranty of 013MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 014General Public License for more details. 015 016You should have received a copy of the GNU General Public License 017along with GNU Classpath; see the file COPYING. If not, write to the 018Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 01902110-1301 USA. 020 021Linking this library statically or dynamically with other modules is 022making a combined work based on this library. Thus, the terms and 023conditions of the GNU General Public License cover the whole 024combination. 025 026As a special exception, the copyright holders of this library give you 027permission to link this library with independent modules to produce an 028executable, regardless of the license terms of these independent 029modules, and to copy and distribute the resulting executable under 030terms of your choice, provided that you also meet, for each linked 031independent module, the terms and conditions of the license of that 032module. An independent module is a module which is not derived from 033or based on this library. If you modify this library, you may extend 034this exception to your version of the library, but you are not 035obligated to do so. If you do not wish to do so, delete this 036exception statement from your version. */ 037 038 039package javax.sound.sampled; 040 041import gnu.classpath.ServiceFactory; 042 043import java.io.File; 044import java.io.IOException; 045import java.io.InputStream; 046import java.io.OutputStream; 047import java.net.URL; 048import java.util.HashSet; 049import java.util.Iterator; 050 051import javax.sound.sampled.spi.AudioFileReader; 052import javax.sound.sampled.spi.AudioFileWriter; 053import javax.sound.sampled.spi.FormatConversionProvider; 054import javax.sound.sampled.spi.MixerProvider; 055 056/** 057 * This clas is the primary interface to the audio system. It contains 058 * a number of static methods which can be used to access this package's 059 * functionality. 060 * 061 * @since 1.3 062 */ 063public class AudioSystem 064{ 065 /** 066 * A constant which can be passed to a number of methods in this package, 067 * to indicate an unspecified value. 068 */ 069 public static final int NOT_SPECIFIED = -1; 070 071 // This class is not instantiable. 072 private AudioSystem() 073 { 074 } 075 076 /** 077 * Return the file format of a given File. 078 * @param f the file to check 079 * @return the format of the file 080 * @throws UnsupportedAudioFileException if the file's format is not 081 * recognized 082 * @throws IOException if there is an I/O error reading the file 083 */ 084 public static AudioFileFormat getAudioFileFormat(File f) 085 throws UnsupportedAudioFileException, IOException 086 { 087 Iterator<AudioFileReader> i = ServiceFactory.lookupProviders(AudioFileReader.class); 088 while (i.hasNext()) 089 { 090 AudioFileReader reader = i.next(); 091 try 092 { 093 return reader.getAudioFileFormat(f); 094 } 095 catch (UnsupportedAudioFileException _) 096 { 097 // Try the next provider. 098 } 099 } 100 throw new UnsupportedAudioFileException("file type not recognized"); 101 } 102 103 /** 104 * Return the file format of a given input stream. 105 * @param is the input stream to check 106 * @return the format of the stream 107 * @throws UnsupportedAudioFileException if the stream's format is not 108 * recognized 109 * @throws IOException if there is an I/O error reading the stream 110 */ 111 public static AudioFileFormat getAudioFileFormat(InputStream is) 112 throws UnsupportedAudioFileException, IOException 113 { 114 Iterator<AudioFileReader> i = ServiceFactory.lookupProviders(AudioFileReader.class); 115 while (i.hasNext()) 116 { 117 AudioFileReader reader = i.next(); 118 try 119 { 120 return reader.getAudioFileFormat(is); 121 } 122 catch (UnsupportedAudioFileException _) 123 { 124 // Try the next provider. 125 } 126 } 127 throw new UnsupportedAudioFileException("input stream type not recognized"); 128 } 129 130 /** 131 * Return the file format of a given URL. 132 * @param url the URL to check 133 * @return the format of the URL 134 * @throws UnsupportedAudioFileException if the URL's format is not 135 * recognized 136 * @throws IOException if there is an I/O error reading the URL 137 */ 138 public static AudioFileFormat getAudioFileFormat(URL url) 139 throws UnsupportedAudioFileException, IOException 140 { 141 Iterator<AudioFileReader> i = ServiceFactory.lookupProviders(AudioFileReader.class); 142 while (i.hasNext()) 143 { 144 AudioFileReader reader = i.next(); 145 try 146 { 147 return reader.getAudioFileFormat(url); 148 } 149 catch (UnsupportedAudioFileException _) 150 { 151 // Try the next provider. 152 } 153 } 154 throw new UnsupportedAudioFileException("URL type not recognized"); 155 } 156 157 /** 158 * Return an array of all the supported AudioFileFormat types. 159 * @return an array of unique types 160 */ 161 public static AudioFileFormat.Type[] getAudioFileTypes() 162 { 163 HashSet<AudioFileFormat.Type> result 164 = new HashSet<AudioFileFormat.Type>(); 165 Iterator<AudioFileWriter> i = ServiceFactory.lookupProviders(AudioFileWriter.class); 166 while (i.hasNext()) 167 { 168 AudioFileWriter writer = i.next(); 169 AudioFileFormat.Type[] types = writer.getAudioFileTypes(); 170 for (int j = 0; j < types.length; ++j) 171 result.add(types[j]); 172 } 173 return result.toArray(new AudioFileFormat.Type[result.size()]); 174 } 175 176 /** 177 * Return an array of all the supported AudioFileFormat types which match the 178 * given audio input stream 179 * @param ais the audio input stream 180 * @return an array of unique types 181 */ 182 public static AudioFileFormat.Type[] getAudioFileTypes(AudioInputStream ais) 183 { 184 HashSet<AudioFileFormat.Type> result 185 = new HashSet<AudioFileFormat.Type>(); 186 Iterator<AudioFileWriter> i = ServiceFactory.lookupProviders(AudioFileWriter.class); 187 while (i.hasNext()) 188 { 189 AudioFileWriter writer = i.next(); 190 AudioFileFormat.Type[] types = writer.getAudioFileTypes(ais); 191 for (int j = 0; j < types.length; ++j) 192 result.add(types[j]); 193 } 194 return result.toArray(new AudioFileFormat.Type[result.size()]); 195 } 196 197 /** 198 * Given an audio input stream, this will try to create a new audio input 199 * stream whose encoding matches the given target encoding. If no provider 200 * offers this conversion, an exception is thrown. 201 * @param targ the target encoding 202 * @param ais the original audio stream 203 * @return a new audio stream 204 * @throws IllegalArgumentException if the conversion cannot be made 205 */ 206 public static AudioInputStream getAudioInputStream(AudioFormat.Encoding targ, 207 AudioInputStream ais) 208 { 209 Iterator<FormatConversionProvider> i = 210 ServiceFactory.lookupProviders(FormatConversionProvider.class); 211 while (i.hasNext()) 212 { 213 FormatConversionProvider prov = i.next(); 214 if (! prov.isConversionSupported(targ, ais.getFormat())) 215 continue; 216 return prov.getAudioInputStream(targ, ais); 217 } 218 throw new IllegalArgumentException("encoding not supported for stream"); 219 } 220 221 /** 222 * Given an audio input stream, this will try to create a new audio input 223 * stream whose format matches the given target format. If no provider 224 * offers this conversion, an exception is thrown. 225 * @param targ the target format 226 * @param ais the original audio stream 227 * @return a new audio stream 228 * @throws IllegalArgumentException if the conversion cannot be made 229 */ 230 public static AudioInputStream getAudioInputStream(AudioFormat targ, 231 AudioInputStream ais) 232 { 233 Iterator<FormatConversionProvider> i = 234 ServiceFactory.lookupProviders(FormatConversionProvider.class); 235 while (i.hasNext()) 236 { 237 FormatConversionProvider prov = i.next(); 238 if (! prov.isConversionSupported(targ, ais.getFormat())) 239 continue; 240 return prov.getAudioInputStream(targ, ais); 241 } 242 throw new IllegalArgumentException("format not supported for stream"); 243 } 244 245 /** 246 * Return an audio input stream for the file. 247 * @param f the file to read 248 * @return an audio input stream for the file 249 * @throws UnsupportedAudioFileException if the file's audio format is not 250 * recognized 251 * @throws IOException if there is an error while reading the file 252 */ 253 public static AudioInputStream getAudioInputStream(File f) 254 throws UnsupportedAudioFileException, IOException 255 { 256 Iterator<AudioFileReader> i = ServiceFactory.lookupProviders(AudioFileReader.class); 257 while (i.hasNext()) 258 { 259 AudioFileReader reader = i.next(); 260 try 261 { 262 return reader.getAudioInputStream(f); 263 } 264 catch (UnsupportedAudioFileException _) 265 { 266 // Try the next provider. 267 } 268 } 269 throw new UnsupportedAudioFileException("file type not recognized"); 270 } 271 272 /** 273 * Return an audio input stream given an input stream. 274 * @param is the input stream 275 * @return an audio input stream 276 * @throws UnsupportedAudioFileException if the input stream's audio format 277 * is not supported by any of the installed providers 278 * @throws IOException if there is an error while reading the input stream 279 */ 280 public static AudioInputStream getAudioInputStream(InputStream is) 281 throws UnsupportedAudioFileException, IOException 282 { 283 Iterator<AudioFileReader> i = ServiceFactory.lookupProviders(AudioFileReader.class); 284 while (i.hasNext()) 285 { 286 AudioFileReader reader = i.next(); 287 try 288 { 289 return reader.getAudioInputStream(is); 290 } 291 catch (UnsupportedAudioFileException _) 292 { 293 // Try the next provider. 294 } 295 } 296 throw new UnsupportedAudioFileException("input stream type not recognized"); 297 } 298 299 /** 300 * Return an audio input stream for the given URL. 301 * @param url the URL 302 * @return an audio input stream 303 * @throws UnsupportedAudioFileException if the URL's audio format is not 304 * supported by any of the installed providers 305 * @throws IOException if there is an error while reading the URL 306 */ 307 public static AudioInputStream getAudioInputStream(URL url) 308 throws UnsupportedAudioFileException, IOException 309 { 310 Iterator<AudioFileReader> i = ServiceFactory.lookupProviders(AudioFileReader.class); 311 while (i.hasNext()) 312 { 313 AudioFileReader reader = i.next(); 314 try 315 { 316 return reader.getAudioInputStream(url); 317 } 318 catch (UnsupportedAudioFileException _) 319 { 320 // Try the next provider. 321 } 322 } 323 throw new UnsupportedAudioFileException("URL type not recognized"); 324 } 325 326 /** 327 * Return a new clip which can be used for playing back an audio stream. 328 * @throws LineUnavailableException if a clip is not available for some 329 * reason 330 * @throws SecurityException if a clip cannot be made for security reasons 331 * @since 1.5 332 */ 333 public static Clip getClip() 334 throws LineUnavailableException 335 { 336 Mixer.Info[] infos = getMixerInfo(); 337 for (int i = 0; i < infos.length; ++i) 338 { 339 Mixer mix = getMixer(infos[i]); 340 Line[] lines = mix.getSourceLines(); 341 for (int j = 0; j < lines.length; ++j) 342 { 343 if (lines[j] instanceof Clip) 344 return (Clip) lines[j]; 345 } 346 } 347 throw new LineUnavailableException("no Clip available"); 348 } 349 350 /** 351 * Return a new clip which can be used for playing back an audio stream. 352 * The clip is obtained from the indicated mixer. 353 * @param info the mixer to use 354 * @throws LineUnavailableException if a clip is not available for some 355 * reason 356 * @throws SecurityException if a clip cannot be made for security reasons 357 * @since 1.5 358 */ 359 public static Clip getClip(Mixer.Info info) 360 throws LineUnavailableException 361 { 362 Mixer mix = getMixer(info); 363 Line[] lines = mix.getSourceLines(); 364 for (int j = 0; j < lines.length; ++j) 365 { 366 if (lines[j] instanceof Clip) 367 return (Clip) lines[j]; 368 } 369 throw new LineUnavailableException("no Clip available"); 370 } 371 372 /** 373 * Return a line matching the provided description. All the providers 374 * on the system are searched for a matching line. 375 * @param info description of the line 376 * @return the matching line 377 * @throws LineUnavailableException if no provider supplies a matching line 378 */ 379 public static Line getLine(Line.Info info) throws LineUnavailableException 380 { 381 Mixer.Info[] infos = getMixerInfo(); 382 for (int i = 0; i < infos.length; ++i) 383 { 384 Mixer mix = getMixer(infos[i]); 385 try 386 { 387 return mix.getLine(info); 388 } 389 catch (LineUnavailableException _) 390 { 391 // Try the next provider. 392 } 393 } 394 throw new LineUnavailableException("no Clip available"); 395 } 396 397 /** 398 * Return a mixer matching the provided description. All the providers 399 * on the system are searched for a matching mixer. 400 * @param info description of the mixer 401 * @return the matching mixer 402 * @throws IllegalArgumentException if no provider supplies a matching mixer 403 */ 404 public static Mixer getMixer(Mixer.Info info) 405 { 406 Iterator<MixerProvider> i = ServiceFactory.lookupProviders(MixerProvider.class); 407 while (i.hasNext()) 408 { 409 MixerProvider prov = i.next(); 410 if (prov.isMixerSupported(info)) 411 return prov.getMixer(info); 412 } 413 throw new IllegalArgumentException("mixer not found"); 414 } 415 416 /** 417 * Return an array of descriptions of all the mixers provided on the system. 418 */ 419 public static Mixer.Info[] getMixerInfo() 420 { 421 HashSet<Mixer.Info> result = new HashSet<Mixer.Info>(); 422 Iterator<MixerProvider> i = ServiceFactory.lookupProviders(MixerProvider.class); 423 while (i.hasNext()) 424 { 425 MixerProvider prov = i.next(); 426 Mixer.Info[] is = prov.getMixerInfo(); 427 for (int j = 0; j < is.length; ++j) 428 result.add(is[j]); 429 } 430 return result.toArray(new Mixer.Info[result.size()]); 431 } 432 433 /** 434 * Return a source data line matching the given audio format. 435 * @param fmt the audio format 436 * @throws LineUnavailableException if no source data line matching 437 * this format is available 438 * @since 1.5 439 */ 440 public static SourceDataLine getSourceDataLine(AudioFormat fmt) 441 throws LineUnavailableException 442 { 443 DataLine.Info info = new DataLine.Info(SourceDataLine.class, fmt); 444 Mixer.Info[] mixers = getMixerInfo(); 445 for (int i = 0; i < mixers.length; ++i) 446 { 447 Mixer mix = getMixer(mixers[i]); 448 if (mix.isLineSupported(info)) 449 return (SourceDataLine) mix.getLine(info); 450 } 451 throw new LineUnavailableException("source data line not found"); 452 } 453 454 /** 455 * Return a target data line matching the given audio format. 456 * @param fmt the audio format 457 * @throws LineUnavailableException if no target data line matching 458 * this format is available 459 * @since 1.5 460 */ 461 public static SourceDataLine getSourceDataLine(AudioFormat fmt, 462 Mixer.Info mixer) 463 throws LineUnavailableException 464 { 465 DataLine.Info info = new DataLine.Info(SourceDataLine.class, fmt); 466 Mixer mix = getMixer(mixer); 467 if (mix.isLineSupported(info)) 468 return (SourceDataLine) mix.getLine(info); 469 throw new LineUnavailableException("source data line not found"); 470 } 471 472 /** 473 * Return an array of descriptions of all the source lines matching 474 * the given line description. 475 * @param info description of the lines to match 476 */ 477 public static Line.Info[] getSourceLineInfo(Line.Info info) 478 { 479 HashSet<Line.Info> result = new HashSet<Line.Info>(); 480 Mixer.Info[] infos = getMixerInfo(); 481 for (int i = 0; i < infos.length; ++i) 482 { 483 Mixer mix = getMixer(infos[i]); 484 Line.Info[] srcs = mix.getSourceLineInfo(info); 485 for (int j = 0; j < srcs.length; ++j) 486 result.add(srcs[j]); 487 } 488 return result.toArray(new Line.Info[result.size()]); 489 } 490 491 /** 492 * Find and return a target data line matching the given audio format. 493 * @param fmt the format to match 494 * @throws LineUnavailableException if no matching line was found 495 * @since 1.5 496 */ 497 public static TargetDataLine getTargetDataLine(AudioFormat fmt) 498 throws LineUnavailableException 499 { 500 DataLine.Info info = new DataLine.Info(TargetDataLine.class, fmt); 501 Mixer.Info[] mixers = getMixerInfo(); 502 for (int i = 0; i < mixers.length; ++i) 503 { 504 Mixer mix = getMixer(mixers[i]); 505 if (mix.isLineSupported(info)) 506 return (TargetDataLine) mix.getLine(info); 507 } 508 throw new LineUnavailableException("target data line not found"); 509 } 510 511 /** 512 * Return a target data line matching the given audio format and 513 * mixer. 514 * @param fmt the audio format 515 * @param mixer the mixer description 516 * @return a target data line 517 * @throws LineUnavailableException if no matching target data line was 518 * found 519 * @since 1.5 520 */ 521 public static TargetDataLine getTargetDataLine(AudioFormat fmt, 522 Mixer.Info mixer) 523 throws LineUnavailableException 524 { 525 DataLine.Info info = new DataLine.Info(TargetDataLine.class, fmt); 526 Mixer mix = getMixer(mixer); 527 if (mix.isLineSupported(info)) 528 return (TargetDataLine) mix.getLine(info); 529 throw new LineUnavailableException("target data line not found"); 530 } 531 532 /** 533 * Given a source encoding, return an array of all target encodings to which 534 * data in this form can be converted. 535 * @param source the source encoding 536 */ 537 public static AudioFormat.Encoding[] getTargetEncodings(AudioFormat.Encoding source) 538 { 539 HashSet<AudioFormat.Encoding> result 540 = new HashSet<AudioFormat.Encoding>(); 541 Iterator<FormatConversionProvider> i = 542 ServiceFactory.lookupProviders(FormatConversionProvider.class); 543 while (i.hasNext()) 544 { 545 FormatConversionProvider prov = i.next(); 546 if (! prov.isSourceEncodingSupported(source)) 547 continue; 548 AudioFormat.Encoding[] es = prov.getTargetEncodings(); 549 for (int j = 0; j < es.length; ++j) 550 result.add(es[j]); 551 } 552 return result.toArray(new AudioFormat.Encoding[result.size()]); 553 } 554 555 /** 556 * Given a source format, return an array of all the target encodings to 557 * which data in this format can be converted. 558 * @param source the source format 559 */ 560 public static AudioFormat.Encoding[] getTargetEncodings(AudioFormat source) 561 { 562 HashSet<AudioFormat.Encoding> result 563 = new HashSet<AudioFormat.Encoding>(); 564 Iterator<FormatConversionProvider> i = 565 ServiceFactory.lookupProviders(FormatConversionProvider.class); 566 while (i.hasNext()) 567 { 568 FormatConversionProvider prov = i.next(); 569 AudioFormat.Encoding[] es = prov.getTargetEncodings(source); 570 for (int j = 0; j < es.length; ++j) 571 result.add(es[j]); 572 } 573 return result.toArray(new AudioFormat.Encoding[result.size()]); 574 } 575 576 /** 577 * Given a target encoding and a source audio format, return an array of all 578 * matching audio formats to which data in this source format can be converted. 579 * @param encoding the target encoding 580 * @param sourceFmt the source format 581 */ 582 public static AudioFormat[] getTargetFormats(AudioFormat.Encoding encoding, 583 AudioFormat sourceFmt) 584 { 585 HashSet<AudioFormat> result = new HashSet<AudioFormat>(); 586 Iterator<FormatConversionProvider> i = 587 ServiceFactory.lookupProviders(FormatConversionProvider.class); 588 while (i.hasNext()) 589 { 590 FormatConversionProvider prov = i.next(); 591 AudioFormat[] es = prov.getTargetFormats(encoding, sourceFmt); 592 for (int j = 0; j < es.length; ++j) 593 result.add(es[j]); 594 } 595 return result.toArray(new AudioFormat[result.size()]); 596 } 597 598 /** 599 * Given a line description, return an array of descriptions of all 600 * the matching target lines. 601 * @param info the line description 602 */ 603 public static Line.Info[] getTargetLineInfo(Line.Info info) 604 { 605 HashSet<Line.Info> result = new HashSet<Line.Info>(); 606 Mixer.Info[] infos = getMixerInfo(); 607 for (int i = 0; i < infos.length; ++i) 608 { 609 Mixer mix = getMixer(infos[i]); 610 Line.Info[] targs = mix.getTargetLineInfo(info); 611 for (int j = 0; j < targs.length; ++j) 612 result.add(targs[j]); 613 } 614 return result.toArray(new Line.Info[result.size()]); 615 } 616 617 /** 618 * Return true if the currently installed providers are able to 619 * convert data from the given source format to the given target encoding. 620 * @param targ the target encoding 621 * @param source the source format 622 */ 623 public static boolean isConversionSupported(AudioFormat.Encoding targ, 624 AudioFormat source) 625 { 626 Iterator<FormatConversionProvider> i 627 = ServiceFactory.lookupProviders(FormatConversionProvider.class); 628 while (i.hasNext()) 629 { 630 FormatConversionProvider prov = i.next(); 631 if (prov.isConversionSupported(targ, source)) 632 return true; 633 } 634 return false; 635 } 636 637 /** 638 * Return true if the currently installed providers are able to convert 639 * the given source format to the given target format. 640 * @param targ the target format 641 * @param source the source format 642 */ 643 public static boolean isConversionSupported(AudioFormat targ, 644 AudioFormat source) 645 { 646 Iterator<FormatConversionProvider> i 647 = ServiceFactory.lookupProviders(FormatConversionProvider.class); 648 while (i.hasNext()) 649 { 650 FormatConversionProvider prov = i.next(); 651 if (prov.isConversionSupported(targ, source)) 652 return true; 653 } 654 return false; 655 } 656 657 private static boolean isFileTypeSupported(AudioFileFormat.Type[] types, 658 AudioFileFormat.Type type) 659 { 660 for (int i = 0; i < types.length; ++i) 661 { 662 if (types[i].equals(type)) 663 return true; 664 } 665 return false; 666 } 667 668 /** 669 * Return true if the given audio file format is supported by one of 670 * the providers installed on the system. 671 * @param type the audio file format type 672 */ 673 public static boolean isFileTypeSupported(AudioFileFormat.Type type) 674 { 675 return isFileTypeSupported(getAudioFileTypes(), type); 676 } 677 678 /** 679 * Return true if the given audio file format is supported for the 680 * given audio input stream by one of the providers installed on the 681 * system. 682 * @param type the audio file format type 683 * @param ais the audio input stream 684 */ 685 public static boolean isFileTypeSupported(AudioFileFormat.Type type, 686 AudioInputStream ais) 687 { 688 return isFileTypeSupported(getAudioFileTypes(ais), type); 689 } 690 691 /** 692 * Return true if some provider on the system supplies a line 693 * matching the argument. 694 * @param info the line to match 695 */ 696 public static boolean isLineSupported(Line.Info info) 697 { 698 Mixer.Info[] infos = getMixerInfo(); 699 for (int i = 0; i < infos.length; ++i) 700 { 701 if (getMixer(infos[i]).isLineSupported(info)) 702 return true; 703 } 704 return false; 705 } 706 707 /** 708 * Write an audio input stream to the given file, using the specified 709 * audio file format. All the providers installed on the system will 710 * be searched to find one that supports this operation. 711 * @param ais the audio input stream to write 712 * @param type the desired audio file format type 713 * @param out the file to write to 714 * @return the number of bytes written 715 * @throws IOException if an I/O error occurs while writing 716 * @throws IllegalArgumentException if the file type is not supported 717 */ 718 public static int write(AudioInputStream ais, AudioFileFormat.Type type, 719 File out) 720 throws IOException 721 { 722 Iterator<AudioFileWriter> i = ServiceFactory.lookupProviders(AudioFileWriter.class); 723 while (i.hasNext()) 724 { 725 AudioFileWriter w = i.next(); 726 if (w.isFileTypeSupported(type, ais)) 727 return w.write(ais, type, out); 728 } 729 throw new IllegalArgumentException("file type not supported by system"); 730 } 731 732 /** 733 * Write an audio input stream to the given output stream, using the 734 * specified audio file format. All the providers installed on the 735 * system will be searched to find one that supports this operation. 736 * @param ais the audio input stream to write 737 * @param type the desired audio file format type 738 * @param os the output stream to write to 739 * @return the number of bytes written 740 * @throws IOException if an I/O error occurs while writing 741 * @throws IllegalArgumentException if the file type is not supported 742 */ 743 public static int write(AudioInputStream ais, AudioFileFormat.Type type, 744 OutputStream os) 745 throws IOException 746 { 747 Iterator<AudioFileWriter> i = ServiceFactory.lookupProviders(AudioFileWriter.class); 748 while (i.hasNext()) 749 { 750 AudioFileWriter w = i.next(); 751 if (w.isFileTypeSupported(type, ais)) 752 return w.write(ais, type, os); 753 } 754 throw new IllegalArgumentException("file type not supported by system"); 755 } 756}