public DataPusher(SourceDataLine sourceLine, AudioInputStream ais) {
   this.ais = ais;
   this.format = ais.getFormat();
   this.source = sourceLine;
 }
 /** Write data to the source data line. */
 public void run() {
   byte[] buffer = null;
   boolean useStream = (ais != null);
   if (useStream) {
     buffer = new byte[BUFFER_SIZE];
   } else {
     buffer = audioData;
   }
   while (wantedState != STATE_STOPPING) {
     // try {
     if (wantedState == STATE_WAITING) {
       // wait for 5 seconds - maybe the clip is to be played again
       if (DEBUG || Printer.debug) Printer.debug("DataPusher.run(): waiting 5 seconds");
       try {
         synchronized (this) {
           threadState = STATE_WAITING;
           wantedState = STATE_STOPPING;
           wait(AUTO_CLOSE_TIME);
         }
       } catch (InterruptedException ie) {
       }
       if (DEBUG || Printer.debug) Printer.debug("DataPusher.run(): waiting finished");
       continue;
     }
     if (newPos >= 0) {
       pos = newPos;
       newPos = -1;
     }
     threadState = STATE_PLAYING;
     int toWrite = BUFFER_SIZE;
     if (useStream) {
       try {
         pos = 0; // always write from beginning of buffer
         // don't use read(byte[]), because some streams
         // may not override that method
         toWrite = ais.read(buffer, 0, buffer.length);
       } catch (java.io.IOException ioe) {
         // end of stream
         toWrite = -1;
       }
     } else {
       if (toWrite > audioDataByteLength - pos) {
         toWrite = audioDataByteLength - pos;
       }
       if (toWrite == 0) {
         toWrite = -1; // end of "stream"
       }
     }
     if (toWrite < 0) {
       if (DEBUG || Printer.debug) Printer.debug("DataPusher.run(): Found end of stream");
       if (!useStream && looping) {
         if (DEBUG || Printer.debug) Printer.debug("DataPusher.run(): setting pos back to 0");
         pos = 0;
         continue;
       }
       if (DEBUG || Printer.debug) Printer.debug("DataPusher.run(): calling drain()");
       wantedState = STATE_WAITING;
       source.drain();
       continue;
     }
     if (DEBUG || Printer.debug)
       Printer.debug("> DataPusher.run(): Writing " + toWrite + " bytes");
     int bytesWritten = source.write(buffer, pos, toWrite);
     pos += bytesWritten;
     if (DEBUG || Printer.debug)
       Printer.debug("< DataPusher.run(): Wrote " + bytesWritten + " bytes");
   }
   threadState = STATE_STOPPING;
   if (DEBUG || Printer.debug) Printer.debug("DataPusher: closing device");
   if (Printer.trace) Printer.trace("DataPusher: source.flush()");
   source.flush();
   if (DEBUG || Printer.trace) Printer.trace("DataPusher: source.stop()");
   source.stop();
   if (DEBUG || Printer.trace) Printer.trace("DataPusher: source.flush()");
   source.flush();
   if (DEBUG || Printer.trace) Printer.trace("DataPusher: source.close()");
   source.close();
   threadState = STATE_STOPPED;
   synchronized (this) {
     pushThread = null;
     notifyAll();
   }
   if (DEBUG || Printer.debug) Printer.debug("DataPusher:end of thread");
 }