/* * AudioSystem.java * * This file is part of Tritonus: http://www.tritonus.org/ */ /* * Copyright (c) 1999 - 2002 by Matthias Pfisterer * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU Library General Public License as published * by the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Library General Public License for more details. * * You should have received a copy of the GNU Library General Public * License along with this program; if not, write to the Free Software * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ /* |<--- this code is formatted to fit into 80 columns --->| */ package javax.sound.sampled; import java.io.File; import java.io.InputStream; import java.io.IOException; import java.io.OutputStream; import java.net.URL; import java.util.Arrays; import java.util.Collection; import java.util.ArrayList; import java.util.HashSet; import java.util.Set; import java.util.Iterator; import javax.sound.sampled.spi.AudioFileReader; import javax.sound.sampled.spi.AudioFileWriter; import javax.sound.sampled.spi.FormatConversionProvider; import javax.sound.sampled.spi.MixerProvider; import org.tritonus.core.TAudioConfig; import org.tritonus.share.TDebug; import org.tritonus.share.ArraySet; public class AudioSystem { public static final int NOT_SPECIFIED = -1; private static final AudioFormat.Encoding[] EMPTY_ENCODING_ARRAY = new AudioFormat.Encoding[0]; private static final AudioFileFormat.Type[] EMPTY_TYPE_ARRAY = new AudioFileFormat.Type[0]; private static final Mixer.Info[] EMPTY_MIXER_INFO_ARRAY = new Mixer.Info[0]; private static final Line.Info[] EMPTY_LINE_INFO_ARRAY = new Line.Info[0]; /** MixerProviderAction for getMixerInfo(). */ private static class GetMixerInfoMixerProviderAction implements MixerProviderAction { private Collection<Mixer.Info> m_mixerInfos = new ArrayList<Mixer.Info>(); public GetMixerInfoMixerProviderAction() { } public boolean handleMixerProvider( MixerProvider mixerProvider) { Mixer.Info[] aMixerInfos = mixerProvider.getMixerInfo(); if (aMixerInfos != null) { // TODO: is this if needed? if (aMixerInfos.length > 0) { if (TDebug.TraceAudioSystem) { TDebug.out("AudioSystem.getMixerInfo(): MixerProvider returns array:"); for (int i = 0; i < aMixerInfos.length; i++) { TDebug.out("" + aMixerInfos[i]); } } } else if (TDebug.TraceAudioSystem) { TDebug.out("AudioSystem.getMixerInfo(): MixerProvider returns empty array."); } m_mixerInfos.addAll(Arrays.asList(aMixerInfos)); } else if (TDebug.TraceAudioSystem) { TDebug.out("AudioSystem.getMixerInfo(): MixerProvider returns null."); } // always continue return false; } public Mixer.Info[] getMixerInfos() { return m_mixerInfos.toArray(EMPTY_MIXER_INFO_ARRAY); } } public static Mixer.Info[] getMixerInfo() { GetMixerInfoMixerProviderAction action = new GetMixerInfoMixerProviderAction(); doMixerProviderIteration(action); Mixer.Info[] infos = action.getMixerInfos(); // TDebug.out("MI length: " + infos.length); return infos; } /** MixerProviderAction for getMixer(). */ private static class GetMixerMixerProviderAction implements MixerProviderAction { private Mixer.Info m_info = null; private Mixer m_mixer = null; public GetMixerMixerProviderAction(Mixer.Info info) { m_info = info; } public boolean handleMixerProvider( MixerProvider mixerProvider) { try { Mixer mixer = mixerProvider.getMixer(m_info); if (m_mixer == null) { m_mixer = mixer; // now interrupt the iteration return true; } } catch (IllegalArgumentException e) { if (TDebug.TraceAudioSystem || TDebug.TraceAllExceptions) { TDebug.out(e); } } // continue the iteration return false; } public Mixer getMixer() { return m_mixer; } } public static Mixer getMixer(Mixer.Info info) { if (info == null) { // TODO: this currently always yields null!!! // but default mixers are handled by some magic in // TMixerProvider info = TAudioConfig.getDefaultMixerInfo(); } GetMixerMixerProviderAction action = new GetMixerMixerProviderAction(info); doMixerProviderIteration(action); Mixer mixer = action.getMixer(); if (mixer != null) { return mixer; } else { throw new IllegalArgumentException("no mixer found for " + info); } } /** MixerAction for getSourceLineInfo(). */ private static class GetSourceLineInfoMixerAction implements MixerAction { private Line.Info m_info = null; private Set<Line.Info> m_infos; public GetSourceLineInfoMixerAction(Line.Info info) { m_info = info; m_infos = new ArraySet<Line.Info>(); } public boolean handleMixer( Mixer mixer) { Line.Info[] infos = mixer.getSourceLineInfo(m_info); m_infos.addAll(Arrays.asList(infos)); // always continue the iteration return false; } public Line.Info[] getInfos() { return m_infos.toArray(EMPTY_LINE_INFO_ARRAY); } } public static Line.Info[] getSourceLineInfo(Line.Info info) { GetSourceLineInfoMixerAction action = new GetSourceLineInfoMixerAction(info); doMixerIteration(action); return action.getInfos(); } /** MixerAction for getTargetLineInfo(). */ private static class GetTargetLineInfoMixerAction implements MixerAction { private Line.Info m_info = null; private Set<Line.Info> m_infos; public GetTargetLineInfoMixerAction(Line.Info info) { m_info = info; m_infos = new ArraySet<Line.Info>(); } public boolean handleMixer( Mixer mixer) { Line.Info[] infos = mixer.getTargetLineInfo(m_info); m_infos.addAll(Arrays.asList(infos)); // always continue the iteration return false; } public Line.Info[] getInfos() { return m_infos.toArray(EMPTY_LINE_INFO_ARRAY); } } public static Line.Info[] getTargetLineInfo(Line.Info info) { GetTargetLineInfoMixerAction action = new GetTargetLineInfoMixerAction(info); doMixerIteration(action); return action.getInfos(); } /** MixerAction for isLineSupported(). */ private static class IsLineSupportedMixerAction implements MixerAction { private Line.Info m_info = null; private boolean m_bSupported = false; public IsLineSupportedMixerAction(Line.Info info) { m_info = info; } public boolean handleMixer( Mixer mixer) { boolean bSupported = mixer.isLineSupported(m_info); m_bSupported |= bSupported; // interrupt the iteration depending on the result return bSupported; } public boolean isSupported() { return m_bSupported; } } public static boolean isLineSupported(Line.Info info) { IsLineSupportedMixerAction action = new IsLineSupportedMixerAction(info); doMixerIteration(action); return action.isSupported(); } /** MixerAction for getLine(). */ private static class GetLineMixerAction implements MixerAction { private Line.Info m_info = null; private Line m_line = null; private boolean m_bLineTypeSupported = false; public GetLineMixerAction(Line.Info info) { m_info = info; } public boolean handleMixer( Mixer mixer) { try { Line line = mixer.getLine(m_info); if (m_line == null) { m_line = line; // interrupt the iteration return true; } } catch (LineUnavailableException e) { m_bLineTypeSupported = true; if (TDebug.TraceAudioSystem || TDebug.TraceAllExceptions) { TDebug.out(e); } } catch (IllegalArgumentException e) { if (TDebug.TraceAudioSystem || TDebug.TraceAllExceptions) { TDebug.out(e); } } // continue the iteration return false; } public Line getLine() { return m_line; } public boolean isLineTypeSupported() { return m_bLineTypeSupported; } } public static Line getLine(Line.Info info) throws LineUnavailableException { GetLineMixerAction action = new GetLineMixerAction(info); doMixerIteration(action); Line line = action.getLine(); if (line != null) { return line; } else if (action.isLineTypeSupported()) { throw new LineUnavailableException("currently no line available due to resource restrictions"); } else { throw new IllegalArgumentException("no mixer supporting this type of line: " + info); } } /** FormatConversionProviderAction for getTargetEncodings(). */ private static class GetTargetEncodingsFormatConversionProviderAction implements FormatConversionProviderAction { private Object m_sourceDescription; private Collection<AudioFormat.Encoding> m_targetEncodings; //$$fb 2000-08-15: added for workaround below public GetTargetEncodingsFormatConversionProviderAction() { this(null); } public GetTargetEncodingsFormatConversionProviderAction( Object sourceDescription) { m_sourceDescription = sourceDescription; m_targetEncodings = new ArraySet<AudioFormat.Encoding>(); } public boolean handleFormatConversionProvider( FormatConversionProvider formatConversionProvider) { // $$fb 2000-03-30 default to empty array AudioFormat.Encoding[] encodings = EMPTY_ENCODING_ARRAY; if (m_sourceDescription instanceof AudioFormat.Encoding) { // TODO: not directely implementable. Contact Sun. //$$fb 2000-08-15: see workaround below /* encodings = formatConversionProvider.getTargetEncodings( (AudioFormat.Encoding) m_sourceDescription); */ } else if (m_sourceDescription instanceof AudioFormat) { encodings = formatConversionProvider.getTargetEncodings( (AudioFormat) m_sourceDescription); } else { // TODO: debug message } m_targetEncodings.addAll(Arrays.asList(encodings)); // continue the iteration return false; } public AudioFormat.Encoding[] getEncodings() { return m_targetEncodings.toArray(EMPTY_ENCODING_ARRAY); } //$$fb 2000-08-15: added for workaround below public void setSourceDescription(Object sourceDescription) { m_sourceDescription = sourceDescription; } } //$$fb 2000-08-15: added for workaround below private static void doEncodingActionWorkaround(boolean bigEndian, AudioFormat.Encoding encoding, GetTargetEncodingsFormatConversionProviderAction action) { AudioFormat format=new AudioFormat( encoding, NOT_SPECIFIED, // sample rate NOT_SPECIFIED, // sample size in bits NOT_SPECIFIED, // channels NOT_SPECIFIED, // frame size NOT_SPECIFIED, // frame rate, bigEndian); action.setSourceDescription(format); doFormatConversionProviderIteration(action); } public static AudioFormat.Encoding[] getTargetEncodings( AudioFormat.Encoding sourceEncoding) { //$$fb 2000-08-15: workaround //return getTargetEncodings((Object) sourceEncoding); GetTargetEncodingsFormatConversionProviderAction action = new GetTargetEncodingsFormatConversionProviderAction(); doEncodingActionWorkaround(false, sourceEncoding, action); doEncodingActionWorkaround(true, sourceEncoding, action); return action.getEncodings(); } public static AudioFormat.Encoding[] getTargetEncodings( AudioFormat sourceFormat) { return getTargetEncodings((Object) sourceFormat); } private static AudioFormat.Encoding[] getTargetEncodings( Object sourceDescription) { GetTargetEncodingsFormatConversionProviderAction action = new GetTargetEncodingsFormatConversionProviderAction(sourceDescription); doFormatConversionProviderIteration(action); return action.getEncodings(); } /** FormatConversionProviderAction for isConversionSupported(). */ private static class IsConversionSupportedFormatConversionProviderAction implements FormatConversionProviderAction { private AudioFormat m_sourceFormat; /* * May be AudioFormat or AudioFormat.Encoding. */ private Object m_targetDescription; private boolean m_bSupported; public IsConversionSupportedFormatConversionProviderAction( AudioFormat sourceFormat, Object targetDescription) { m_sourceFormat = sourceFormat; m_targetDescription = targetDescription; m_bSupported = false; } public boolean handleFormatConversionProvider( FormatConversionProvider formatConversionProvider) { boolean bSupported = false; if (m_targetDescription instanceof AudioFormat.Encoding) { bSupported = formatConversionProvider.isConversionSupported( (AudioFormat.Encoding) m_targetDescription, m_sourceFormat); } else if (m_targetDescription instanceof AudioFormat) { bSupported = formatConversionProvider.isConversionSupported( (AudioFormat) m_targetDescription, m_sourceFormat); } else { // TODO: debug message } m_bSupported |= bSupported; // interrupt the iteration depending on the result return bSupported; } public boolean isSupported() { return m_bSupported; } } public static boolean isConversionSupported( AudioFormat.Encoding targetEncoding, AudioFormat sourceFormat) { IsConversionSupportedFormatConversionProviderAction action = new IsConversionSupportedFormatConversionProviderAction(sourceFormat, targetEncoding); doFormatConversionProviderIteration(action); return action.isSupported(); } /** FormatConversionProviderAction for getAudioInputStream(). */ private static class GetAudioInputStreamFormatConversionProviderAction implements FormatConversionProviderAction { private AudioInputStream m_sourceAudioInputStream; private Object m_targetDescription; private AudioInputStream m_targetAudioInputStream; public GetAudioInputStreamFormatConversionProviderAction( AudioInputStream audioInputStream, Object targetDescription) { m_sourceAudioInputStream = audioInputStream; m_targetDescription = targetDescription; m_targetAudioInputStream = null; } public boolean handleFormatConversionProvider( FormatConversionProvider formatConversionProvider) { AudioInputStream audioInputStream = null; try { if (m_targetDescription instanceof AudioFormat.Encoding) { audioInputStream = formatConversionProvider.getAudioInputStream( (AudioFormat.Encoding) m_targetDescription, m_sourceAudioInputStream); } else if (m_targetDescription instanceof AudioFormat) { audioInputStream = formatConversionProvider.getAudioInputStream( (AudioFormat) m_targetDescription, m_sourceAudioInputStream); } else { // TODO: debug message } m_targetAudioInputStream = audioInputStream; // interrupt the iteration return true; } catch (IllegalArgumentException e) { if (TDebug.TraceAudioSystem || TDebug.TraceAllExceptions) { TDebug.out(e); } } // continue the iteration return false; } public AudioInputStream getAudioInputStream() { return m_targetAudioInputStream; } } public static AudioInputStream getAudioInputStream( AudioFormat.Encoding targetEncoding, AudioInputStream sourceStream) { return getAudioInputStreamImpl(targetEncoding, sourceStream); } private static AudioInputStream getAudioInputStreamImpl( Object targetDescription, AudioInputStream sourceStream) { GetAudioInputStreamFormatConversionProviderAction action = new GetAudioInputStreamFormatConversionProviderAction(sourceStream, targetDescription); doFormatConversionProviderIteration(action); AudioInputStream audioInputStream = action.getAudioInputStream(); if (audioInputStream != null) { return audioInputStream; } else { throw new IllegalArgumentException("conversion not supported"); } } public static AudioFormat[] getTargetFormats( AudioFormat.Encoding targetEncoding, AudioFormat sourceFormat) { // TODO: return null; } public static boolean isConversionSupported( AudioFormat targetFormat, AudioFormat sourceFormat) { IsConversionSupportedFormatConversionProviderAction action = new IsConversionSupportedFormatConversionProviderAction(sourceFormat, targetFormat); doFormatConversionProviderIteration(action); return action.isSupported(); } public static AudioInputStream getAudioInputStream( AudioFormat targetFormat, AudioInputStream sourceStream) { return getAudioInputStreamImpl(targetFormat, sourceStream); } // $$fb 19 Dec 99: what about cascaded conversions ? // we'll never have an alround-converter doing all possible conversions. // we could implement an algorithm that, if no conversion is available, // in a second step a conversion to PCM is tried, followed by a conversion from // PCM to the requested target format. // we might even introduce a third level for inter-PCM-conversion. // e.g. we want to convert from aLaw 8000Hz to uLaw 44100Hz. // 1. the first round we won't find a direct converter // 2. try to find a converter from aLaw 8000 to PCM 44100 // we won't find it. // 3. third level: try to find a converter from alaw 8000 to PCM 8000 // we'll find one. // then find a converter from PCM 8000 to PCM 44100 // let's say we have that already. // then find a converter from PCM 44100 to ulaw 44100. // I think that sounds more impossible than it is, when // we have a powerful PCM-PCM converter. /* public static AudioInputStream getAudioInputStream(AudioFormat audioFormat, AudioInputStream audioInputStream) { Iterator formatConversionProviders = TAudioConfig.getFormatConversionProviders(); while (formatConversionProviders.hasNext()) { FormatConversionProvider formatConversionProvider = (FormatConversionProvider) formatConversionProviders.next(); if (TDebug.TraceAudioSystem) { System.out.print("AudioSystem.getAudioInputStream(AudioFormat, AudioInputStream): asking FormatConversionProvider: " + formatConversionProvider + "..."); } try { AudioInputStream outputStream = formatConversionProvider.getConvertedStream(audioFormat, audioInputStream); if (TDebug.TraceAudioSystem) { TDebug.out("ok"); } return outputStream; } catch (IllegalArgumentException e) { if (TDebug.TraceAudioSystem || TDebug.TraceAllExceptions) { TDebug.out("failed"); TDebug.out(e); } } } if (TDebug.TraceAudioSystem) { TDebug.out("AudioSystem.getAudioInputStream(AudioFormat, AudioInputStream): no suitable FormatConversionProvider found. Returning null."); } return null; } */ /* public static AudioInputStream getAudioInputStream(Type encoding, AudioInputStream audioInputStream) { AudioFormat inputFormat = audioInputStream.getFormat(); // $$fb 19 Dec 99: Here I think, sample size in bits and framesize should // be set to NOT_SPECIFIED, as we cannot assume that it stays // the same with the new encoding. */ /* $$mp19991220: Yes, possible optimisation: find all formats with the given encoding that can be generated by conversion from the stream. Then pick the one nearest to the original format. */ /* AudioFormat outputFormat = new AudioFormat(encoding, inputFormat.getSampleRate(), inputFormat.getSampleSizeInBits(), inputFormat.getChannels(), inputFormat.getFrameSize(), inputFormat.getFrameRate(), inputFormat.isBigEndian()); return getAudioInputStream(outputFormat, audioInputStream); } */ /** AudioFileReaderAction for getAudioFileFormat(). */ private static class GetAudioFileFormatAudioFileReaderAction implements AudioFileReaderAction { private Object m_source = null; private AudioFileFormat m_audioFileFormat = null; public GetAudioFileFormatAudioFileReaderAction(Object source) { m_source = source; } public boolean handleAudioFileReader( AudioFileReader audioFileReader) throws IOException { AudioFileFormat audioFileFormat = null; try { if (m_source instanceof InputStream) { audioFileFormat = audioFileReader.getAudioFileFormat((InputStream) m_source); } else if (m_source instanceof File) { audioFileFormat = audioFileReader.getAudioFileFormat((File) m_source); } else if (m_source instanceof URL) { audioFileFormat = audioFileReader.getAudioFileFormat((URL) m_source); } else { // TODO: debug message } if (m_audioFileFormat == null) { m_audioFileFormat = audioFileFormat; // interrupt the iteration return true; } } catch (UnsupportedAudioFileException e) { if (TDebug.TraceAudioSystem || TDebug.TraceAllExceptions) { TDebug.out(e); } } // continue the iteration return false; } public AudioFileFormat getAudioFileFormat() { return m_audioFileFormat; } } public static AudioFileFormat getAudioFileFormat( InputStream inputStream) throws UnsupportedAudioFileException, IOException { return getAudioFileFormatImpl(inputStream); } public static AudioFileFormat getAudioFileFormat(URL url) throws UnsupportedAudioFileException, IOException { return getAudioFileFormatImpl(url); } public static AudioFileFormat getAudioFileFormat(File file) throws UnsupportedAudioFileException, IOException { return getAudioFileFormatImpl(file); } private static AudioFileFormat getAudioFileFormatImpl( Object source) throws UnsupportedAudioFileException, IOException { GetAudioFileFormatAudioFileReaderAction action = new GetAudioFileFormatAudioFileReaderAction(source); doAudioFileReaderIteration(action); AudioFileFormat audioFileFormat = action.getAudioFileFormat(); if (audioFileFormat != null) { return audioFileFormat; } else { throw new UnsupportedAudioFileException("format not supported"); } } /** AudioFileReaderAction for getAudioInputStream(). */ private static class GetAudioInputStreamAudioFileReaderAction implements AudioFileReaderAction { private Object m_source = null; private AudioInputStream m_audioInputStream = null; public GetAudioInputStreamAudioFileReaderAction(Object source) { m_source = source; } public boolean handleAudioFileReader( AudioFileReader audioFileReader) throws IOException { AudioInputStream audioInputStream = null; try { if (m_source instanceof InputStream) { audioInputStream = audioFileReader.getAudioInputStream((InputStream) m_source); } else if (m_source instanceof File) { audioInputStream = audioFileReader.getAudioInputStream((File) m_source); } else if (m_source instanceof URL) { audioInputStream = audioFileReader.getAudioInputStream((URL) m_source); } else { // TODO: debug message } if (m_audioInputStream == null) { m_audioInputStream = audioInputStream; // interrupt the iteration return true; } } catch (UnsupportedAudioFileException e) { if (TDebug.TraceAudioSystem || TDebug.TraceAllExceptions) { TDebug.out(e); } } // continue the iteration return false; } public AudioInputStream getAudioInputStream() { return m_audioInputStream; } } public static AudioInputStream getAudioInputStream(InputStream inputStream) throws UnsupportedAudioFileException, IOException { return getAudioInputStreamImpl(inputStream); } public static AudioInputStream getAudioInputStream(URL url) throws UnsupportedAudioFileException, IOException { return getAudioInputStreamImpl(url); } public static AudioInputStream getAudioInputStream(File file) throws UnsupportedAudioFileException, IOException { return getAudioInputStreamImpl(file); } private static AudioInputStream getAudioInputStreamImpl( Object source) throws UnsupportedAudioFileException, IOException { GetAudioInputStreamAudioFileReaderAction action = new GetAudioInputStreamAudioFileReaderAction(source); doAudioFileReaderIteration(action); AudioInputStream audioInputStream = action.getAudioInputStream(); if (audioInputStream != null) { return audioInputStream; } else { throw new UnsupportedAudioFileException("format not supported"); } } public static AudioFileFormat.Type[] getAudioFileTypes() { Set<AudioFileFormat.Type> supportedTypes = new HashSet<AudioFileFormat.Type>(); Iterator audioFileWriters = TAudioConfig.getAudioFileWriters(); if (TDebug.TraceAudioSystem) { TDebug.out(">AudioSystem.getAudioFileTypes()"); } while (audioFileWriters.hasNext()) { AudioFileWriter audioFileProvider = (AudioFileWriter) audioFileWriters.next(); if (TDebug.TraceAudioSystem) { TDebug.out("trying AudioFileWriter: " + audioFileProvider); } AudioFileFormat.Type[] aSupportedTypes = audioFileProvider.getAudioFileTypes(); if (TDebug.TraceAudioSystem) { TDebug.out("this AudioFileWriter supports the following Types:"); } for (int i = 0; i < aSupportedTypes.length; i++) { if (TDebug.TraceAudioSystem) { TDebug.out(aSupportedTypes[i].toString()); } supportedTypes.add(aSupportedTypes[i]); } } if (TDebug.TraceAudioSystem) { TDebug.out("< returning " + supportedTypes.size() + " types."); } return supportedTypes.toArray(EMPTY_TYPE_ARRAY); } /** AudioFileWriterAction for isFileTypeSupported(). */ private static class IsFileTypeSupportedAudioFileWriterAction implements AudioFileWriterAction { private AudioFileFormat.Type m_fileType; private AudioInputStream m_audioInputStream; private boolean m_bSupported; public IsFileTypeSupportedAudioFileWriterAction( AudioFileFormat.Type fileType, AudioInputStream audioInputStream) { m_fileType = fileType; m_audioInputStream = audioInputStream; m_bSupported = false; } public boolean handleAudioFileWriter( AudioFileWriter mixer) { boolean bSupported = false; if (m_audioInputStream == null) { bSupported = mixer.isFileTypeSupported( m_fileType); } else { bSupported = mixer.isFileTypeSupported( m_fileType, m_audioInputStream); } m_bSupported |= bSupported; // interrupt the iteration depending on the result return bSupported; } public boolean isSupported() { return m_bSupported; } } public static boolean isFileTypeSupported( AudioFileFormat.Type fileType) { return isFileTypeSupported(fileType, null); } public static AudioFileFormat.Type[] getAudioFileTypes( AudioInputStream audioInputStream) { Set<AudioFileFormat.Type> supportedTypes = new HashSet<AudioFileFormat.Type>(); Iterator audioFileWriters = TAudioConfig.getAudioFileWriters(); if (TDebug.TraceAudioSystem) { TDebug.out(">AudioSystem.getAudioFileTypes()"); } while (audioFileWriters.hasNext()) { AudioFileWriter audioFileProvider = (AudioFileWriter) audioFileWriters.next(); if (TDebug.TraceAudioSystem) { TDebug.out("trying AudioFileWriter: " + audioFileProvider); } AudioFileFormat.Type[] aSupportedTypes = audioFileProvider.getAudioFileTypes(audioInputStream); if (TDebug.TraceAudioSystem) { TDebug.out("this AudioFileWriter supports the following Types:"); } for (int i = 0; i < aSupportedTypes.length; i++) { if (TDebug.TraceAudioSystem) { TDebug.out(aSupportedTypes[i].toString()); } supportedTypes.add(aSupportedTypes[i]); } } if (TDebug.TraceAudioSystem) { TDebug.out("< returning " + supportedTypes.size() + " types."); } return supportedTypes.toArray(EMPTY_TYPE_ARRAY); } public static boolean isFileTypeSupported( AudioFileFormat.Type fileType, AudioInputStream audioInputStream) { IsFileTypeSupportedAudioFileWriterAction action = new IsFileTypeSupportedAudioFileWriterAction( fileType, audioInputStream); try { doAudioFileWriterIteration(action); } catch (IOException e) { if (TDebug.TraceAllExceptions) { TDebug.out(e); } } return action.isSupported(); } /** AudioFileWriterAction for write(). */ private static class WriteAudioFileWriterAction implements AudioFileWriterAction { private AudioInputStream m_audioInputStream; private AudioFileFormat.Type m_fileType; private Object m_destination; private int m_nWritten; public WriteAudioFileWriterAction( AudioInputStream audioInputStream, AudioFileFormat.Type fileType, Object destination) { m_audioInputStream = audioInputStream; m_fileType = fileType; m_destination = destination; m_nWritten = -1; } // $$fb 2000-04-02: variable should be called "audioFileWriter" (too much copy&paste :) public boolean handleAudioFileWriter( AudioFileWriter audioFileWriter) throws IOException { int nWritten = -1; // $$fb 2000-04-02: need to check whether this audioFileWriter is actually // capable of handling this file type ! if (TDebug.TraceAudioSystem) { TDebug.out(">AudioSystem.handleAudioFileWriter("+audioFileWriter.getClass().getName()+") checking for type "+m_fileType); } if (!audioFileWriter.isFileTypeSupported(m_fileType)) { if (TDebug.TraceAudioSystem) { TDebug.out("< is not capable of handling this file type"); } return false; } try { if (m_destination instanceof OutputStream) { // $$fb 2000-04-02: s.a. nWritten = audioFileWriter.write( m_audioInputStream, m_fileType, (OutputStream) m_destination); } else if (m_destination instanceof File) { // $$fb 2000-04-02: s.a. nWritten = audioFileWriter.write( m_audioInputStream, m_fileType, (File) m_destination); } else { // TODO: debug message } m_nWritten = nWritten; if (TDebug.TraceAudioSystem) { TDebug.out("< wrote "+nWritten+" bytes"); } // interrupt the iteration return true; } catch (IllegalArgumentException e) { if (TDebug.TraceAudioSystem || TDebug.TraceAllExceptions) { TDebug.out(e); } } if (TDebug.TraceAudioSystem) { TDebug.out("< does not support this file type."); } // continue the iteration return false; } public int getWritten() { return m_nWritten; } } public static int write(AudioInputStream inputStream, AudioFileFormat.Type fileType, OutputStream outputStream) throws IOException { return writeImpl(inputStream, fileType, outputStream); } public static int write(AudioInputStream inputStream, AudioFileFormat.Type fileType, File file) throws IOException { return writeImpl(inputStream, fileType, file); } private static int writeImpl(AudioInputStream audioInputStream, AudioFileFormat.Type fileType, Object destination) throws IOException { WriteAudioFileWriterAction action = new WriteAudioFileWriterAction( audioInputStream, fileType, destination); doAudioFileWriterIteration(action); int nWritten = action.getWritten(); if (nWritten == -1) { throw new IllegalArgumentException("format not supported"); } else { return nWritten; } } ////////////////////////////////////////////////////////////// // // auxiliary methods and interfaces // ////////////////////////////////////////////////////////////// private static interface MixerProviderAction { public boolean handleMixerProvider(MixerProvider mixerProvider); } /** Iterates over the available MixerProviders. * For each MixerProvider, the mathod handleMixerProvider() of * the passed MixerProviderAction is called with the MixerProvider * in question as the only argument. */ private static void doMixerProviderIteration( MixerProviderAction action) { Iterator mixerProviders = TAudioConfig.getMixerProviders(); boolean bCompleted = false; if (TDebug.TraceAudioSystem) { TDebug.out(">AudioSystem.doMixerProviderIteration()"); } while (mixerProviders.hasNext() && ! bCompleted) { MixerProvider mixerProvider = (MixerProvider) mixerProviders.next(); if (TDebug.TraceAudioSystem) { TDebug.out("handling MixerProvider: " + mixerProvider); } bCompleted = action.handleMixerProvider(mixerProvider); } if (TDebug.TraceAudioSystem) { TDebug.out("< completed="+bCompleted); } } private static interface MixerAction { public boolean handleMixer(Mixer mixer); } /** Iterates over the available MixerProviders. * For each MixerProvider, the mathod handleMixerProvider() of * the passed MixerProviderAction is called with the MixerProvider * in question as the only argument. */ private static void doMixerIteration( MixerAction action) { Mixer.Info[] mixerInfos = getMixerInfo(); boolean bCompleted = false; if (TDebug.TraceAudioSystem) { TDebug.out(">AudioSystem.doMixerIteration()"); } for (int nMixer = 0; nMixer < mixerInfos.length && ! bCompleted; nMixer++) { Mixer mixer = getMixer(mixerInfos[nMixer]); if (TDebug.TraceAudioSystem) { TDebug.out("handling Mixer: " + mixer); } bCompleted = action.handleMixer(mixer); } if (TDebug.TraceAudioSystem) { TDebug.out("< completed="+bCompleted); } } private static interface FormatConversionProviderAction { public boolean handleFormatConversionProvider(FormatConversionProvider formatConversionProvider); // throws IOException; } /** Iterates over the available FormatConversionProviders. * For each FormatConversionProvider, the mathod handleFormatConversionProvider() of * the passed FormatConversionProviderAction is called with the FormatConversionProvider * in question as the only argument. */ private static void doFormatConversionProviderIteration( FormatConversionProviderAction action) // throws IOException { Iterator formatConversionProviders = TAudioConfig.getFormatConversionProviders(); boolean bCompleted = false; if (TDebug.TraceAudioSystem) { TDebug.out(">AudioSystem.doFormatConversionProviderIteration()"); } while (formatConversionProviders.hasNext() && ! bCompleted) { FormatConversionProvider formatConversionProvider = (FormatConversionProvider) formatConversionProviders.next(); if (TDebug.TraceAudioSystem) { TDebug.out("handling FormatConversionProvider: " + formatConversionProvider); } bCompleted = action.handleFormatConversionProvider(formatConversionProvider); } if (TDebug.TraceAudioSystem) { TDebug.out("< completed="+bCompleted); } } private static interface AudioFileReaderAction { public boolean handleAudioFileReader(AudioFileReader audioFileReader) throws IOException; } /** Iterates over the available AudioFileReaders. * For each AudioFileReader, the mathod handleAudioFileReader() of * the passed AudioFileReaderAction is called with the AudioFileReader * in question as the only argument. */ private static void doAudioFileReaderIteration( AudioFileReaderAction action) throws IOException { Iterator audioFileReaders = TAudioConfig.getAudioFileReaders(); boolean bCompleted = false; if (TDebug.TraceAudioSystem) { TDebug.out(">AudioSystem.doAudioFileReaderIteration()"); } while (audioFileReaders.hasNext() && ! bCompleted) { AudioFileReader audioFileReader = (AudioFileReader) audioFileReaders.next(); if (TDebug.TraceAudioSystem) { TDebug.out("handling AudioFileReader: " + audioFileReader); } bCompleted = action.handleAudioFileReader(audioFileReader); } if (TDebug.TraceAudioSystem) { TDebug.out("< completed="+bCompleted); } } private static interface AudioFileWriterAction { public boolean handleAudioFileWriter(AudioFileWriter audioFileWriter) throws IOException; } /** Iterates over the available AudioFileWriters. * For each AudioFileWriter, the mathod handleAudioFileWriter() of * the passed AudioFileWriterAction is called with the AudioFileWriter * in question as the only argument. */ private static void doAudioFileWriterIteration( AudioFileWriterAction action) throws IOException { Iterator audioFileWriters = TAudioConfig.getAudioFileWriters(); boolean bCompleted = false; if (TDebug.TraceAudioSystem) { TDebug.out(">AudioSystem.doAudioFileWriterIteration()"); } while (audioFileWriters.hasNext() && ! bCompleted) { AudioFileWriter audioFileWriter = (AudioFileWriter) audioFileWriters.next(); if (TDebug.TraceAudioSystem) { TDebug.out("handling AudioFileWriter: " + audioFileWriter); } bCompleted = action.handleAudioFileWriter(audioFileWriter); } if (TDebug.TraceAudioSystem) { TDebug.out("< completed="+bCompleted); } } } /*** AudioSystem.java ***/