Save This Page
Home » openjdk-7 » com.sun.media » sound » [javadoc | source]
    1   /*
    2    * Copyright (c) 2002, 2007, 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 javax.sound.sampled;
   29   
   30   /**
   31    * Class to write an AudioInputStream to a SourceDataLine.
   32    * Was previously an inner class in various classes like JavaSoundAudioClip
   33    * and sun.audio.AudioDevice.
   34    * It auto-opens and closes the SourceDataLine.
   35    *
   36    * @author Kara Kytle
   37    * @author Florian Bomers
   38    */
   39   
   40   public class DataPusher implements Runnable {
   41   
   42       private static final int AUTO_CLOSE_TIME = 5000;
   43       private static final boolean DEBUG = false;
   44   
   45       private SourceDataLine source = null;
   46       private AudioFormat format = null;
   47   
   48       // stream as source data
   49       private AudioInputStream ais = null;
   50   
   51       // byte array as source data
   52       private byte[] audioData = null;
   53       private int audioDataByteLength = 0;
   54       private int pos;
   55       private int newPos = -1;
   56       private boolean looping;
   57   
   58       private Thread pushThread = null;
   59       private int wantedState;
   60       private int threadState;
   61   
   62       private final int STATE_NONE = 0;
   63       private final int STATE_PLAYING = 1;
   64       private final int STATE_WAITING = 2;
   65       private final int STATE_STOPPING = 3;
   66       private final int STATE_STOPPED = 4;
   67       private final int BUFFER_SIZE = 16384;
   68   
   69       public DataPusher(SourceDataLine sourceLine, AudioFormat format, byte[] audioData, int byteLength) {
   70           this.audioData = audioData;
   71           this.audioDataByteLength = byteLength;
   72           this.format = format;
   73           this.source = sourceLine;
   74       }
   75   
   76       public DataPusher(SourceDataLine sourceLine, AudioInputStream ais) {
   77           this.ais = ais;
   78           this.format = ais.getFormat();
   79           this.source = sourceLine;
   80       }
   81   
   82       public synchronized void start() {
   83           start(false);
   84       }
   85   
   86       public synchronized void start(boolean loop) {
   87           if (DEBUG || Printer.debug) Printer.debug("> DataPusher.start(loop="+loop+")");
   88           try {
   89               if (threadState == STATE_STOPPING) {
   90                   // wait that the thread has finished stopping
   91                   if (DEBUG || Printer.trace)Printer.trace("DataPusher.start(): calling stop()");
   92                   stop();
   93               }
   94               looping = loop;
   95               newPos = 0;
   96               wantedState = STATE_PLAYING;
   97               if (!source.isOpen()) {
   98                   if (DEBUG || Printer.trace)Printer.trace("DataPusher: source.open()");
   99                   source.open(format);
  100               }
  101               if (DEBUG || Printer.trace)Printer.trace("DataPusher: source.flush()");
  102               source.flush();
  103               if (DEBUG || Printer.trace)Printer.trace("DataPusher: source.start()");
  104               source.start();
  105               if (pushThread == null) {
  106                   if (DEBUG || Printer.debug) Printer.debug("DataPusher.start(): Starting push");
  107                   pushThread = JSSecurityManager.createThread(this,
  108                                                               null,   // name
  109                                                               false,  // daemon
  110                                                               -1,    // priority
  111                                                               true); // doStart
  112               }
  113               notifyAll();
  114           } catch (Exception e) {
  115               if (DEBUG || Printer.err) e.printStackTrace();
  116           }
  117           if (DEBUG || Printer.debug) Printer.debug("< DataPusher.start(loop="+loop+")");
  118       }
  119   
  120   
  121       public synchronized void stop() {
  122           if (DEBUG || Printer.debug) Printer.debug("> DataPusher.stop()");
  123           if (threadState == STATE_STOPPING
  124               || threadState == STATE_STOPPED
  125               || pushThread == null) {
  126               if (DEBUG || Printer.debug) Printer.debug("DataPusher.stop(): nothing to do");
  127               return;
  128           }
  129           if (DEBUG || Printer.debug) Printer.debug("DataPusher.stop(): Stopping push");
  130   
  131           wantedState = STATE_WAITING;
  132           if (source != null) {
  133               if (DEBUG || Printer.trace)Printer.trace("DataPusher: source.flush()");
  134               source.flush();
  135           }
  136           notifyAll();
  137           int maxWaitCount = 50; // 5 seconds
  138           while ((maxWaitCount-- >= 0) && (threadState == STATE_PLAYING)) {
  139               try {
  140                   wait(100);
  141               } catch (InterruptedException e) {  }
  142           }
  143           if (DEBUG || Printer.debug) Printer.debug("< DataPusher.stop()");
  144       }
  145   
  146       synchronized void close() {
  147           if (source != null) {
  148                   if (DEBUG || Printer.trace)Printer.trace("DataPusher.close(): source.close()");
  149                   source.close();
  150           }
  151       }
  152   
  153       /**
  154        * Write data to the source data line.
  155        */
  156       public void run() {
  157           byte[] buffer = null;
  158           boolean useStream = (ais != null);
  159           if (useStream) {
  160               buffer = new byte[BUFFER_SIZE];
  161           } else {
  162               buffer = audioData;
  163           }
  164           while (wantedState != STATE_STOPPING) {
  165               //try {
  166                   if (wantedState == STATE_WAITING) {
  167                       // wait for 5 seconds - maybe the clip is to be played again
  168                       if (DEBUG || Printer.debug)Printer.debug("DataPusher.run(): waiting 5 seconds");
  169                       try {
  170                           synchronized(this) {
  171                                   threadState = STATE_WAITING;
  172                                   wantedState = STATE_STOPPING;
  173                                   wait(AUTO_CLOSE_TIME);
  174                           }
  175                       } catch (InterruptedException ie) {}
  176                       if (DEBUG || Printer.debug)Printer.debug("DataPusher.run(): waiting finished");
  177                       continue;
  178                   }
  179                   if (newPos >= 0) {
  180                           pos = newPos;
  181                           newPos = -1;
  182                   }
  183                   threadState = STATE_PLAYING;
  184                   int toWrite = BUFFER_SIZE;
  185                   if (useStream) {
  186                       try {
  187                           pos = 0; // always write from beginning of buffer
  188                           // don't use read(byte[]), because some streams
  189                           // may not override that method
  190                           toWrite = ais.read(buffer, 0, buffer.length);
  191                       } catch (java.io.IOException ioe) {
  192                           // end of stream
  193                           toWrite = -1;
  194                       }
  195                   } else {
  196                       if (toWrite > audioDataByteLength - pos) {
  197                           toWrite = audioDataByteLength - pos;
  198                       }
  199                       if (toWrite == 0) {
  200                           toWrite = -1; // end of "stream"
  201                       }
  202                   }
  203                   if (toWrite < 0) {
  204                       if (DEBUG || Printer.debug) Printer.debug("DataPusher.run(): Found end of stream");
  205                           if (!useStream && looping) {
  206                               if (DEBUG || Printer.debug)Printer.debug("DataPusher.run(): setting pos back to 0");
  207                               pos = 0;
  208                               continue;
  209                           }
  210                       if (DEBUG || Printer.debug)Printer.debug("DataPusher.run(): calling drain()");
  211                       wantedState = STATE_WAITING;
  212                       source.drain();
  213                       continue;
  214                   }
  215                   if (DEBUG || Printer.debug) Printer.debug("> DataPusher.run(): Writing " + toWrite + " bytes");
  216                       int bytesWritten = source.write(buffer, pos, toWrite);
  217                       pos += bytesWritten;
  218                   if (DEBUG || Printer.debug) Printer.debug("< DataPusher.run(): Wrote " + bytesWritten + " bytes");
  219           }
  220           threadState = STATE_STOPPING;
  221           if (DEBUG || Printer.debug)Printer.debug("DataPusher: closing device");
  222           if (Printer.trace)Printer.trace("DataPusher: source.flush()");
  223           source.flush();
  224           if (DEBUG || Printer.trace)Printer.trace("DataPusher: source.stop()");
  225           source.stop();
  226           if (DEBUG || Printer.trace)Printer.trace("DataPusher: source.flush()");
  227           source.flush();
  228           if (DEBUG || Printer.trace)Printer.trace("DataPusher: source.close()");
  229           source.close();
  230           threadState = STATE_STOPPED;
  231           synchronized (this) {
  232                   pushThread = null;
  233                   notifyAll();
  234           }
  235           if (DEBUG || Printer.debug)Printer.debug("DataPusher:end of thread");
  236       }
  237   
  238   } // class DataPusher

Save This Page
Home » openjdk-7 » com.sun.media » sound » [javadoc | source]