429 lines · 11.5 KB · Java
RawDownload
/* * Copyright (c) 1999, 2003, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License version 2 only, as * published by the Free Software Foundation.  Oracle designates this * particular file as subject to the "Classpath" exception as provided * by Oracle in the LICENSE file that accompanied this code. * * This code 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 General Public License * version 2 for more details (a copy is included in the LICENSE file that * accompanied this code). * * You should have received a copy of the GNU General Public License version * 2 along with this work; if not, write to the Free Software Foundation, * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. * * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA * or visit www.oracle.com if you need additional information or have any * questions. */ package sun.audio; import java.util.Hashtable;import java.util.Vector;import java.util.Enumeration;import java.io.IOException;import java.io.InputStream;import java.io.BufferedInputStream;import java.io.OutputStream;import java.io.ByteArrayInputStream; import javax.sound.sampled.*;import javax.sound.midi.*;import com.sun.media.sound.DataPusher;import com.sun.media.sound.Toolkit; /** * This class provides an interface to the Headspace Audio engine through * the Java Sound API. * * This class emulates systems with multiple audio channels, mixing * multiple streams for the workstation's single-channel device. * * @see AudioData * @see AudioDataStream * @see AudioStream * @see AudioStreamSequence * @see ContinuousAudioDataStream * @author David Rivas * @author Kara Kytle * @author Jan Borgersen * @author Florian Bomers */ public class    AudioDevice {     private boolean DEBUG = false  /*true*/ ;     /** Hashtable of audio clips / input streams. */    private Hashtable clipStreams;     private Vector infos;     /** Are we currently playing audio? */    private boolean playing = false;     /** Handle to the JS audio mixer. */    private Mixer mixer = null;       /**     * The default audio player. This audio player is initialized     * automatically.     */    public static final AudioDevice device = new AudioDevice();     /**     * Create an AudioDevice instance.     */    private AudioDevice() {         clipStreams = new Hashtable();        infos = new Vector();    }      private synchronized void startSampled( AudioInputStream as,                                            InputStream in ) throws UnsupportedAudioFileException,                                  LineUnavailableException {         Info info = null;        DataPusher datapusher = null;        DataLine.Info lineinfo = null;        SourceDataLine sourcedataline = null;         // if ALAW or ULAW, we must convert....        as = Toolkit.getPCMConvertedAudioInputStream(as);         if( as==null ) {            // could not convert            return;        }         lineinfo = new DataLine.Info(SourceDataLine.class,                                     as.getFormat());        if( !(AudioSystem.isLineSupported(lineinfo))) {            return;        }        sourcedataline = (SourceDataLine)AudioSystem.getLine(lineinfo);        datapusher = new DataPusher(sourcedataline, as);         info = new Info( null, in, datapusher );        infos.addElement( info );         datapusher.start();    }     private synchronized void startMidi( InputStream bis,                                         InputStream in ) throws InvalidMidiDataException,                                  MidiUnavailableException  {         Sequencer sequencer = null;        Info info = null;         sequencer = MidiSystem.getSequencer( );        sequencer.open();        try {            sequencer.setSequence( bis );        } catch( IOException e ) {            throw new InvalidMidiDataException( e.getMessage() );        }         info = new Info( sequencer, in, null );         infos.addElement( info );         // fix for bug 4302884: Audio device is not released when AudioClip stops        sequencer.addMetaEventListener(info);         sequencer.start();     }       /**     *  Open an audio channel.     */    public synchronized void openChannel(InputStream in) {          if(DEBUG) {            System.out.println("AudioDevice: openChannel");            System.out.println("input stream =" + in);        }         Info info = null;         // is this already playing?  if so, then just return        for(int i=0; i<infos.size(); i++) {            info = (AudioDevice.Info)infos.elementAt(i);            if( info.in == in ) {                 return;            }        }          AudioInputStream as = null;         if( in instanceof AudioStream ) {             if ( ((AudioStream)in).midiformat != null ) {                 // it's a midi file                try {                    startMidi( ((AudioStream)in).stream, in );                } catch (Exception e) {                    return;                }              } else if( ((AudioStream)in).ais != null ) {                 // it's sampled audio                try {                    startSampled( ((AudioStream)in).ais, in );                } catch (Exception e) {                    return;                }             }        } else if (in instanceof AudioDataStream ) {            if (in instanceof ContinuousAudioDataStream) {                try {                    AudioInputStream ais = new AudioInputStream(in,                                                                ((AudioDataStream)in).getAudioData().format,                                                                AudioSystem.NOT_SPECIFIED);                    startSampled(ais, in );                } catch (Exception e) {                    return;                }            }            else {                try {                    AudioInputStream ais = new AudioInputStream(in,                                                                ((AudioDataStream)in).getAudioData().format,                                                                ((AudioDataStream)in).getAudioData().buffer.length);                    startSampled(ais, in );                } catch (Exception e) {                    return;                }            }        } else {            BufferedInputStream bis = new BufferedInputStream( in, 1024 );             try {                 try {                    as = AudioSystem.getAudioInputStream(bis);                } catch(IOException ioe) {                    return;                }                 startSampled( as, in );             } catch( UnsupportedAudioFileException e ) {                 try {                    try {                        MidiFileFormat mff =                            MidiSystem.getMidiFileFormat( bis );                    } catch(IOException ioe1) {                        return;                    }                     startMidi( bis, in );                  } catch( InvalidMidiDataException e1 ) {                     // $$jb:08.01.99: adding this section to make some of our other                    // legacy classes work.....                    // not MIDI either, special case handling for all others                     AudioFormat defformat = new AudioFormat( AudioFormat.Encoding.ULAW,                                                             8000, 8, 1, 1, 8000, true );                    try {                        AudioInputStream defaif = new AudioInputStream( bis,                                                                        defformat, AudioSystem.NOT_SPECIFIED);                        startSampled( defaif, in );                    } catch (UnsupportedAudioFileException es) {                        return;                    } catch (LineUnavailableException es2) {                        return;                    }                 } catch( MidiUnavailableException e2 ) {                     // could not open sequence                    return;                }             } catch( LineUnavailableException e ) {                 return;            }        }         // don't forget adjust for a new stream.        notify();    }      /**     *  Close an audio channel.     */    public synchronized void closeChannel(InputStream in) {         if(DEBUG) {            System.out.println("AudioDevice.closeChannel");        }         if (in == null) return;         // can't go anywhere here!         Info info;         for(int i=0; i<infos.size(); i++) {             info = (AudioDevice.Info)infos.elementAt(i);             if( info.in == in ) {                 if( info.sequencer != null ) {                     info.sequencer.stop();                    //info.sequencer.close();                    infos.removeElement( info );                 } else if( info.datapusher != null ) {                     info.datapusher.stop();                    infos.removeElement( info );                }            }        }        notify();    }      /**     * Open the device (done automatically)     */    public synchronized void open() {         // $$jb: 06.24.99: This is done on a per-stream        // basis using the new JS API now.    }      /**     * Close the device (done automatically)     */    public synchronized void close() {         // $$jb: 06.24.99: This is done on a per-stream        // basis using the new JS API now.     }      /**     * Play open audio stream(s)     */    public void play() {         // $$jb: 06.24.99:  Holdover from old architechture ...        // we now open/close the devices as needed on a per-stream        // basis using the JavaSound API.         if (DEBUG) {            System.out.println("exiting play()");        }    }     /**     * Close streams     */    public synchronized void closeStreams() {         Info info;         for(int i=0; i<infos.size(); i++) {             info = (AudioDevice.Info)infos.elementAt(i);             if( info.sequencer != null ) {                 info.sequencer.stop();                info.sequencer.close();                infos.removeElement( info );             } else if( info.datapusher != null ) {                 info.datapusher.stop();                infos.removeElement( info );            }        }          if (DEBUG) {            System.err.println("Audio Device: Streams all closed.");        }        // Empty the hash table.        clipStreams = new Hashtable();        infos = new Vector();    }     /**     * Number of channels currently open.     */    public int openChannels() {        return infos.size();    }     /**     * Make the debug info print out.     */    void setVerbose(boolean v) {        DEBUG = v;    }          // INFO CLASS     class Info implements MetaEventListener {         Sequencer   sequencer;        InputStream in;        DataPusher  datapusher;         Info( Sequencer sequencer, InputStream in, DataPusher datapusher ) {             this.sequencer  = sequencer;            this.in         = in;            this.datapusher = datapusher;        }         public void meta(MetaMessage event) {            if (event.getType() == 47 && sequencer != null) {                sequencer.close();            }        }    }   }