Path: blob/aarch64-shenandoah-jdk8u272-b10/jdk/src/share/classes/sun/audio/AudioDevice.java
38829 views
/*1* Copyright (c) 1999, 2013, Oracle and/or its affiliates. All rights reserved.2* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.3*4* This code is free software; you can redistribute it and/or modify it5* under the terms of the GNU General Public License version 2 only, as6* published by the Free Software Foundation. Oracle designates this7* particular file as subject to the "Classpath" exception as provided8* by Oracle in the LICENSE file that accompanied this code.9*10* This code is distributed in the hope that it will be useful, but WITHOUT11* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or12* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License13* version 2 for more details (a copy is included in the LICENSE file that14* accompanied this code).15*16* You should have received a copy of the GNU General Public License version17* 2 along with this work; if not, write to the Free Software Foundation,18* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.19*20* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA21* or visit www.oracle.com if you need additional information or have any22* questions.23*/2425package sun.audio;2627import java.util.Hashtable;28import java.util.Vector;29import java.io.IOException;30import java.io.InputStream;31import java.io.BufferedInputStream;3233import javax.sound.sampled.*;34import javax.sound.midi.*;35import com.sun.media.sound.DataPusher;36import com.sun.media.sound.Toolkit;3738/**39* This class provides an interface to the Headspace Audio engine through40* the Java Sound API.41*42* This class emulates systems with multiple audio channels, mixing43* multiple streams for the workstation's single-channel device.44*45* @see AudioData46* @see AudioDataStream47* @see AudioStream48* @see AudioStreamSequence49* @see ContinuousAudioDataStream50* @author David Rivas51* @author Kara Kytle52* @author Jan Borgersen53* @author Florian Bomers54*/5556public final class AudioDevice {5758private boolean DEBUG = false /*true*/ ;5960/** Hashtable of audio clips / input streams. */61private Hashtable clipStreams;6263private Vector infos;6465/** Are we currently playing audio? */66private boolean playing = false;6768/** Handle to the JS audio mixer. */69private Mixer mixer = null;70717273/**74* The default audio player. This audio player is initialized75* automatically.76*/77public static final AudioDevice device = new AudioDevice();7879/**80* Create an AudioDevice instance.81*/82private AudioDevice() {8384clipStreams = new Hashtable();85infos = new Vector();86}878889private synchronized void startSampled( AudioInputStream as,90InputStream in ) throws UnsupportedAudioFileException,91LineUnavailableException {9293Info info = null;94DataPusher datapusher = null;95DataLine.Info lineinfo = null;96SourceDataLine sourcedataline = null;9798// if ALAW or ULAW, we must convert....99as = Toolkit.getPCMConvertedAudioInputStream(as);100101if( as==null ) {102// could not convert103return;104}105106lineinfo = new DataLine.Info(SourceDataLine.class,107as.getFormat());108if( !(AudioSystem.isLineSupported(lineinfo))) {109return;110}111sourcedataline = (SourceDataLine)AudioSystem.getLine(lineinfo);112datapusher = new DataPusher(sourcedataline, as);113114info = new Info( null, in, datapusher );115infos.addElement( info );116117datapusher.start();118}119120private synchronized void startMidi( InputStream bis,121InputStream in ) throws InvalidMidiDataException,122MidiUnavailableException {123124Sequencer sequencer = null;125Info info = null;126127sequencer = MidiSystem.getSequencer( );128sequencer.open();129try {130sequencer.setSequence( bis );131} catch( IOException e ) {132throw new InvalidMidiDataException( e.getMessage() );133}134135info = new Info( sequencer, in, null );136137infos.addElement( info );138139// fix for bug 4302884: Audio device is not released when AudioClip stops140sequencer.addMetaEventListener(info);141142sequencer.start();143144}145146147148/**149* Open an audio channel.150*/151public synchronized void openChannel(InputStream in) {152153154if(DEBUG) {155System.out.println("AudioDevice: openChannel");156System.out.println("input stream =" + in);157}158159Info info = null;160161// is this already playing? if so, then just return162for(int i=0; i<infos.size(); i++) {163info = (AudioDevice.Info)infos.elementAt(i);164if( info.in == in ) {165166return;167}168}169170171AudioInputStream as = null;172173if( in instanceof AudioStream ) {174175if ( ((AudioStream)in).midiformat != null ) {176177// it's a midi file178try {179startMidi( ((AudioStream)in).stream, in );180} catch (Exception e) {181return;182}183184185} else if( ((AudioStream)in).ais != null ) {186187// it's sampled audio188try {189startSampled( ((AudioStream)in).ais, in );190} catch (Exception e) {191return;192}193194}195} else if (in instanceof AudioDataStream ) {196if (in instanceof ContinuousAudioDataStream) {197try {198AudioInputStream ais = new AudioInputStream(in,199((AudioDataStream)in).getAudioData().format,200AudioSystem.NOT_SPECIFIED);201startSampled(ais, in );202} catch (Exception e) {203return;204}205}206else {207try {208AudioInputStream ais = new AudioInputStream(in,209((AudioDataStream)in).getAudioData().format,210((AudioDataStream)in).getAudioData().buffer.length);211startSampled(ais, in );212} catch (Exception e) {213return;214}215}216} else {217BufferedInputStream bis = new BufferedInputStream( in, 1024 );218219try {220221try {222as = AudioSystem.getAudioInputStream(bis);223} catch(IOException ioe) {224return;225}226227startSampled( as, in );228229} catch( UnsupportedAudioFileException e ) {230231try {232try {233MidiFileFormat mff =234MidiSystem.getMidiFileFormat( bis );235} catch(IOException ioe1) {236return;237}238239startMidi( bis, in );240241242} catch( InvalidMidiDataException e1 ) {243244// $$jb:08.01.99: adding this section to make some of our other245// legacy classes work.....246// not MIDI either, special case handling for all others247248AudioFormat defformat = new AudioFormat( AudioFormat.Encoding.ULAW,2498000, 8, 1, 1, 8000, true );250try {251AudioInputStream defaif = new AudioInputStream( bis,252defformat, AudioSystem.NOT_SPECIFIED);253startSampled( defaif, in );254} catch (UnsupportedAudioFileException es) {255return;256} catch (LineUnavailableException es2) {257return;258}259260} catch( MidiUnavailableException e2 ) {261262// could not open sequence263return;264}265266} catch( LineUnavailableException e ) {267268return;269}270}271272// don't forget adjust for a new stream.273notify();274}275276277/**278* Close an audio channel.279*/280public synchronized void closeChannel(InputStream in) {281282if(DEBUG) {283System.out.println("AudioDevice.closeChannel");284}285286if (in == null) return; // can't go anywhere here!287288Info info;289290for(int i=0; i<infos.size(); i++) {291292info = (AudioDevice.Info)infos.elementAt(i);293294if( info.in == in ) {295296if( info.sequencer != null ) {297298info.sequencer.stop();299//info.sequencer.close();300infos.removeElement( info );301302} else if( info.datapusher != null ) {303304info.datapusher.stop();305infos.removeElement( info );306}307}308}309notify();310}311312313/**314* Open the device (done automatically)315*/316public synchronized void open() {317318// $$jb: 06.24.99: This is done on a per-stream319// basis using the new JS API now.320}321322323/**324* Close the device (done automatically)325*/326public synchronized void close() {327328// $$jb: 06.24.99: This is done on a per-stream329// basis using the new JS API now.330331}332333334/**335* Play open audio stream(s)336*/337public void play() {338339// $$jb: 06.24.99: Holdover from old architechture ...340// we now open/close the devices as needed on a per-stream341// basis using the JavaSound API.342343if (DEBUG) {344System.out.println("exiting play()");345}346}347348/**349* Close streams350*/351public synchronized void closeStreams() {352353Info info;354355for(int i=0; i<infos.size(); i++) {356357info = (AudioDevice.Info)infos.elementAt(i);358359if( info.sequencer != null ) {360361info.sequencer.stop();362info.sequencer.close();363infos.removeElement( info );364365} else if( info.datapusher != null ) {366367info.datapusher.stop();368infos.removeElement( info );369}370}371372373if (DEBUG) {374System.err.println("Audio Device: Streams all closed.");375}376// Empty the hash table.377clipStreams = new Hashtable();378infos = new Vector();379}380381/**382* Number of channels currently open.383*/384public int openChannels() {385return infos.size();386}387388/**389* Make the debug info print out.390*/391void setVerbose(boolean v) {392DEBUG = v;393}394395396397398399400// INFO CLASS401402final class Info implements MetaEventListener {403404final Sequencer sequencer;405final InputStream in;406final DataPusher datapusher;407408Info( Sequencer sequencer, InputStream in, DataPusher datapusher ) {409410this.sequencer = sequencer;411this.in = in;412this.datapusher = datapusher;413}414415public void meta(MetaMessage event) {416if (event.getType() == 47 && sequencer != null) {417sequencer.close();418}419}420}421422423424}425426427