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