< prev index next >

src/java.desktop/share/classes/com/sun/media/sound/JavaSoundAudioClip.java

Print this page


   1 /*
   2  * Copyright (c) 1999, 2016, Oracle and/or its affiliates. All rights reserved.
   3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
   4  *
   5  * This code is free software; you can redistribute it and/or modify it
   6  * under the terms of the GNU General Public License version 2 only, as
   7  * published by the Free Software Foundation.  Oracle designates this
   8  * particular file as subject to the "Classpath" exception as provided
   9  * by Oracle in the LICENSE file that accompanied this code.
  10  *
  11  * This code is distributed in the hope that it will be useful, but WITHOUT
  12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  13  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  14  * version 2 for more details (a copy is included in the LICENSE file that
  15  * accompanied this code).
  16  *
  17  * You should have received a copy of the GNU General Public License version
  18  * 2 along with this work; if not, write to the Free Software Foundation,
  19  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  20  *
  21  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  22  * or visit www.oracle.com if you need additional information or have any
  23  * questions.
  24  */
  25 
  26 package com.sun.media.sound;
  27 
  28 import java.applet.AudioClip;
  29 import java.io.BufferedInputStream;
  30 import java.io.ByteArrayOutputStream;
  31 import java.io.IOException;
  32 import java.io.InputStream;


  33 
  34 import javax.sound.midi.InvalidMidiDataException;
  35 import javax.sound.midi.MetaEventListener;
  36 import javax.sound.midi.MetaMessage;
  37 import javax.sound.midi.MidiFileFormat;
  38 import javax.sound.midi.MidiSystem;
  39 import javax.sound.midi.MidiUnavailableException;
  40 import javax.sound.midi.Sequence;
  41 import javax.sound.midi.Sequencer;
  42 import javax.sound.sampled.AudioFormat;
  43 import javax.sound.sampled.AudioInputStream;
  44 import javax.sound.sampled.AudioSystem;
  45 import javax.sound.sampled.Clip;
  46 import javax.sound.sampled.DataLine;
  47 import javax.sound.sampled.LineEvent;
  48 import javax.sound.sampled.LineListener;
  49 import javax.sound.sampled.SourceDataLine;
  50 import javax.sound.sampled.UnsupportedAudioFileException;
  51 
  52 /**


  59 public final class JavaSoundAudioClip implements AudioClip, MetaEventListener, LineListener {
  60 
  61     private static final boolean DEBUG = false;
  62     private static final int BUFFER_SIZE = 16384; // number of bytes written each time to the source data line
  63 
  64     private long lastPlayCall = 0;
  65     private static final int MINIMUM_PLAY_DELAY = 30;
  66 
  67     private byte loadedAudio[] = null;
  68     private int loadedAudioByteLength = 0;
  69     private AudioFormat loadedAudioFormat = null;
  70 
  71     private AutoClosingClip clip = null;
  72     private boolean clipLooping = false;
  73 
  74     private DataPusher datapusher = null;
  75 
  76     private Sequencer sequencer = null;
  77     private Sequence sequence = null;
  78     private boolean sequencerloop = false;

  79 
  80     /**
  81      * used for determining how many samples is the
  82      * threshhold between playing as a Clip and streaming
  83      * from the file.
  84      *
  85      * $$jb: 11.07.99: the engine has a limit of 1M
  86      * samples to play as a Clip, so compare this number
  87      * with the number of samples in the stream.
  88      *
  89      */
  90     private static final long CLIP_THRESHOLD = 1048576;
  91     //private final static long CLIP_THRESHOLD = 1;
  92     private static final int STREAM_BUFFER_SIZE = 1024;
  93 
  94     public JavaSoundAudioClip(InputStream in) throws IOException {




















  95         if (DEBUG || Printer.debug)Printer.debug("JavaSoundAudioClip.<init>");
  96 
  97         BufferedInputStream bis = new BufferedInputStream(in, STREAM_BUFFER_SIZE);
  98         bis.mark(STREAM_BUFFER_SIZE);
  99         boolean success = false;
 100         try {
 101             AudioInputStream as = AudioSystem.getAudioInputStream(bis);
 102             // load the stream data into memory
 103             success = loadAudioData(as);
 104 
 105             if (success) {
 106                 success = false;
 107                 if (loadedAudioByteLength < CLIP_THRESHOLD) {
 108                     success = createClip();
 109                 }
 110                 if (!success) {
 111                     success = createSourceDataLine();
 112                 }
 113             }
 114         } catch (UnsupportedAudioFileException e) {
 115             // not an audio file
 116             try {
 117                 MidiFileFormat mff = MidiSystem.getMidiFileFormat(bis);
 118                 success = createSequencer(bis);
 119             } catch (InvalidMidiDataException e1) {
 120                 success = false;
 121             }
 122         }
 123         if (!success) {
 124             throw new IOException("Unable to create AudioClip from input stream");
 125         }
 126     }
 127 
 128     @Override
 129     public synchronized void play() {



 130         startImpl(false);
 131     }
 132 
 133     @Override
 134     public synchronized void loop() {



 135         startImpl(true);
 136     }
 137 
 138     private synchronized void startImpl(boolean loop) {
 139         // hack for some applets that call the start method very rapidly...
 140         long currentTime = System.currentTimeMillis();
 141         long diff = currentTime - lastPlayCall;
 142         if (diff < MINIMUM_PLAY_DELAY) {
 143             if (DEBUG || Printer.debug) Printer.debug("JavaSoundAudioClip.startImpl(loop="+loop+"): abort - too rapdly");
 144             return;
 145         }
 146         lastPlayCall = currentTime;
 147 
 148         if (DEBUG || Printer.debug) Printer.debug("JavaSoundAudioClip.startImpl(loop="+loop+")");
 149         try {
 150             if (clip != null) {
 151                 if (!clip.isOpen()) {
 152                     if (DEBUG || Printer.trace)Printer.trace("JavaSoundAudioClip: clip.open()");
 153                     clip.open(loadedAudioFormat, loadedAudio, 0, loadedAudioByteLength);
 154                 } else {


 189                         if (DEBUG || Printer.err)e1.printStackTrace();
 190                     } catch (MidiUnavailableException e2) {
 191                         if (DEBUG || Printer.err)e2.printStackTrace();
 192                     }
 193                 }
 194                 sequencer.addMetaEventListener(this);
 195                 try {
 196                     sequencer.start();
 197                 } catch (Exception e) {
 198                     if (DEBUG || Printer.err) e.printStackTrace();
 199                 }
 200                 if (DEBUG || Printer.debug)Printer.debug("Sequencer should be playing/looping");
 201             }
 202         } catch (Exception e) {
 203             if (DEBUG || Printer.err)e.printStackTrace();
 204         }
 205     }
 206 
 207     @Override
 208     public synchronized void stop() {



 209 
 210         if (DEBUG || Printer.debug)Printer.debug("JavaSoundAudioClip->stop()");
 211         lastPlayCall = 0;
 212 
 213         if (clip != null) {
 214             try {
 215                 if (DEBUG || Printer.trace)Printer.trace("JavaSoundAudioClip: clip.flush()");
 216                 clip.flush();
 217             } catch (Exception e1) {
 218                 if (Printer.err) e1.printStackTrace();
 219             }
 220             try {
 221                 if (DEBUG || Printer.trace)Printer.trace("JavaSoundAudioClip: clip.stop()");
 222                 clip.stop();
 223             } catch (Exception e2) {
 224                 if (Printer.err) e2.printStackTrace();
 225             }
 226             if (DEBUG || Printer.debug)Printer.debug("Clip should be stopped");
 227 
 228         } else if (datapusher != null) {


   1 /*
   2  * Copyright (c) 1999, 2018, Oracle and/or its affiliates. All rights reserved.
   3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
   4  *
   5  * This code is free software; you can redistribute it and/or modify it
   6  * under the terms of the GNU General Public License version 2 only, as
   7  * published by the Free Software Foundation.  Oracle designates this
   8  * particular file as subject to the "Classpath" exception as provided
   9  * by Oracle in the LICENSE file that accompanied this code.
  10  *
  11  * This code is distributed in the hope that it will be useful, but WITHOUT
  12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  13  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  14  * version 2 for more details (a copy is included in the LICENSE file that
  15  * accompanied this code).
  16  *
  17  * You should have received a copy of the GNU General Public License version
  18  * 2 along with this work; if not, write to the Free Software Foundation,
  19  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  20  *
  21  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  22  * or visit www.oracle.com if you need additional information or have any
  23  * questions.
  24  */
  25 
  26 package com.sun.media.sound;
  27 
  28 import java.applet.AudioClip;
  29 import java.io.BufferedInputStream;
  30 import java.io.ByteArrayOutputStream;
  31 import java.io.IOException;
  32 import java.io.InputStream;
  33 import java.net.URL;
  34 import java.net.URLConnection;
  35 
  36 import javax.sound.midi.InvalidMidiDataException;
  37 import javax.sound.midi.MetaEventListener;
  38 import javax.sound.midi.MetaMessage;
  39 import javax.sound.midi.MidiFileFormat;
  40 import javax.sound.midi.MidiSystem;
  41 import javax.sound.midi.MidiUnavailableException;
  42 import javax.sound.midi.Sequence;
  43 import javax.sound.midi.Sequencer;
  44 import javax.sound.sampled.AudioFormat;
  45 import javax.sound.sampled.AudioInputStream;
  46 import javax.sound.sampled.AudioSystem;
  47 import javax.sound.sampled.Clip;
  48 import javax.sound.sampled.DataLine;
  49 import javax.sound.sampled.LineEvent;
  50 import javax.sound.sampled.LineListener;
  51 import javax.sound.sampled.SourceDataLine;
  52 import javax.sound.sampled.UnsupportedAudioFileException;
  53 
  54 /**


  61 public final class JavaSoundAudioClip implements AudioClip, MetaEventListener, LineListener {
  62 
  63     private static final boolean DEBUG = false;
  64     private static final int BUFFER_SIZE = 16384; // number of bytes written each time to the source data line
  65 
  66     private long lastPlayCall = 0;
  67     private static final int MINIMUM_PLAY_DELAY = 30;
  68 
  69     private byte loadedAudio[] = null;
  70     private int loadedAudioByteLength = 0;
  71     private AudioFormat loadedAudioFormat = null;
  72 
  73     private AutoClosingClip clip = null;
  74     private boolean clipLooping = false;
  75 
  76     private DataPusher datapusher = null;
  77 
  78     private Sequencer sequencer = null;
  79     private Sequence sequence = null;
  80     private boolean sequencerloop = false;
  81     private volatile boolean success;
  82 
  83     /**
  84      * used for determining how many samples is the
  85      * threshhold between playing as a Clip and streaming
  86      * from the file.
  87      *
  88      * $$jb: 11.07.99: the engine has a limit of 1M
  89      * samples to play as a Clip, so compare this number
  90      * with the number of samples in the stream.
  91      *
  92      */
  93     private static final long CLIP_THRESHOLD = 1048576;
  94     //private final static long CLIP_THRESHOLD = 1;
  95     private static final int STREAM_BUFFER_SIZE = 1024;
  96 
  97     public static JavaSoundAudioClip create(final URLConnection uc) {
  98         JavaSoundAudioClip clip = new JavaSoundAudioClip();
  99         try {
 100             clip.init(uc.getInputStream());
 101         } catch (final Exception ignored) {
 102             // AudioClip will be no-op if some exception will occurred
 103         }
 104         return clip;
 105     }
 106 
 107     public static JavaSoundAudioClip create(final URL url) {
 108         JavaSoundAudioClip clip = new JavaSoundAudioClip();
 109         try {
 110             clip.init(url.openStream());
 111         } catch (final Exception ignored) {
 112             // AudioClip will be no-op if some exception will occurred
 113         }
 114         return clip;
 115     }
 116 
 117     private void init(InputStream in) throws IOException {
 118         if (DEBUG || Printer.debug)Printer.debug("JavaSoundAudioClip.<init>");
 119 
 120         BufferedInputStream bis = new BufferedInputStream(in, STREAM_BUFFER_SIZE);
 121         bis.mark(STREAM_BUFFER_SIZE);

 122         try {
 123             AudioInputStream as = AudioSystem.getAudioInputStream(bis);
 124             // load the stream data into memory
 125             success = loadAudioData(as);
 126 
 127             if (success) {
 128                 success = false;
 129                 if (loadedAudioByteLength < CLIP_THRESHOLD) {
 130                     success = createClip();
 131                 }
 132                 if (!success) {
 133                     success = createSourceDataLine();
 134                 }
 135             }
 136         } catch (UnsupportedAudioFileException e) {
 137             // not an audio file
 138             try {
 139                 MidiFileFormat mff = MidiSystem.getMidiFileFormat(bis);
 140                 success = createSequencer(bis);
 141             } catch (InvalidMidiDataException e1) {
 142                 success = false;
 143             }
 144         }



 145     }
 146 
 147     @Override
 148     public synchronized void play() {
 149         if (!success) {
 150             return;
 151         }
 152         startImpl(false);
 153     }
 154 
 155     @Override
 156     public synchronized void loop() {
 157         if (!success) {
 158             return;
 159         }
 160         startImpl(true);
 161     }
 162 
 163     private synchronized void startImpl(boolean loop) {
 164         // hack for some applets that call the start method very rapidly...
 165         long currentTime = System.currentTimeMillis();
 166         long diff = currentTime - lastPlayCall;
 167         if (diff < MINIMUM_PLAY_DELAY) {
 168             if (DEBUG || Printer.debug) Printer.debug("JavaSoundAudioClip.startImpl(loop="+loop+"): abort - too rapdly");
 169             return;
 170         }
 171         lastPlayCall = currentTime;
 172 
 173         if (DEBUG || Printer.debug) Printer.debug("JavaSoundAudioClip.startImpl(loop="+loop+")");
 174         try {
 175             if (clip != null) {
 176                 if (!clip.isOpen()) {
 177                     if (DEBUG || Printer.trace)Printer.trace("JavaSoundAudioClip: clip.open()");
 178                     clip.open(loadedAudioFormat, loadedAudio, 0, loadedAudioByteLength);
 179                 } else {


 214                         if (DEBUG || Printer.err)e1.printStackTrace();
 215                     } catch (MidiUnavailableException e2) {
 216                         if (DEBUG || Printer.err)e2.printStackTrace();
 217                     }
 218                 }
 219                 sequencer.addMetaEventListener(this);
 220                 try {
 221                     sequencer.start();
 222                 } catch (Exception e) {
 223                     if (DEBUG || Printer.err) e.printStackTrace();
 224                 }
 225                 if (DEBUG || Printer.debug)Printer.debug("Sequencer should be playing/looping");
 226             }
 227         } catch (Exception e) {
 228             if (DEBUG || Printer.err)e.printStackTrace();
 229         }
 230     }
 231 
 232     @Override
 233     public synchronized void stop() {
 234         if (!success) {
 235             return;
 236         }
 237 
 238         if (DEBUG || Printer.debug)Printer.debug("JavaSoundAudioClip->stop()");
 239         lastPlayCall = 0;
 240 
 241         if (clip != null) {
 242             try {
 243                 if (DEBUG || Printer.trace)Printer.trace("JavaSoundAudioClip: clip.flush()");
 244                 clip.flush();
 245             } catch (Exception e1) {
 246                 if (Printer.err) e1.printStackTrace();
 247             }
 248             try {
 249                 if (DEBUG || Printer.trace)Printer.trace("JavaSoundAudioClip: clip.stop()");
 250                 clip.stop();
 251             } catch (Exception e2) {
 252                 if (Printer.err) e2.printStackTrace();
 253             }
 254             if (DEBUG || Printer.debug)Printer.debug("Clip should be stopped");
 255 
 256         } else if (datapusher != null) {


< prev index next >