/* JEsd
 * Copyright (C) 1999 JCraft Inc.
 *  
 * Written by: 1999 ymnk
 *   
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Library General Public License
 * as published by the Free Software Foundation; either version 2 of
 * the License, or (at your option) any later version.
   
 * This program 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 Library General Public License for more details.
 * 
 * You should have received a copy of the GNU Library General Public
 * License along with this program; if not, write to the Free Software
 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
 */

package com.jcraft.jesd;

//import javax.media.sound.midi.*;
//import javax.media.sound.sampled.*;
import javax.sound.midi.*;
import javax.sound.sampled.*;

class StreamPlayer extends Player implements LineListener{
  int format;
  int rate;
  String name;
  int left_vol_scale=100;
  int right_vol_scale=100;

  SourceDataLine outputLine=null;
  byte[] buffer=null;
  Thread thread=null;
  int frameSizeInBytes;
  int bufferLengthInBytes;

  StreamPlayer(int format, int rate, String name){
    super();
    this.format=format;
    this.rate=rate;
    this.name=name;

    try {
      // A hack for working around a bug in J2SE Plug-in.                
      // If this code is missing, many redundant file retrieving,
      // 'GET /META-INF/services/javax.sound.sampled.spi.MixerProvider'
      // will occur.
      // This hack was invented by Matthias.Pfisterer@GMX.DE.
//      ClassLoader originalClassLoader=null;
//      try{
//        originalClassLoader=Thread.currentThread().getContextClassLoader();
//	Thread.currentThread().setContextClassLoader(ClassLoader.getSystemClassLoader());
//      }
//      catch(Exception ee){
//        //System.out.println(ee);
//      }
      //

      AudioFormat audioFormat = 
	new AudioFormat((float)rate, 
			((format&JEsd.ESD_MASK_BITS)==JEsd.ESD_BITS16)?16:8,
			((format&JEsd.ESD_MASK_CHAN)==JEsd.ESD_STEREO)?2:1,
			true,  // PCM_Signed
			false  // littleEndian
			);
      DataLine.Info info = 
	new DataLine.Info(SourceDataLine.class,
//			  null, 
//			  null, 
//			  new Class[0], 
			  audioFormat, 
			  AudioSystem.NOT_SPECIFIED);
      if (!AudioSystem.isLineSupported(info)) {
	//System.out.println("Line " + info + " not supported.");
	return;
      }

      try{
	outputLine = (SourceDataLine) AudioSystem.getLine(info);
	//int outputBufferSize = outputLine.getBufferSize();
	outputLine.addLineListener(this);
	outputLine.open(audioFormat/*, outputBufferSize*/);
      } 
      catch (LineUnavailableException ex) { 
	System.out.println("Unable to open the sourceDataLine: " + ex);
	System.exit(1);
	return;
      } 
      catch (IllegalArgumentException ex) { 
	System.out.println("Illegal Argument: " + ex);
	return;
      }

      frameSizeInBytes = audioFormat.getFrameSize();
      int bufferLengthInFrames = outputLine.getBufferSize()/frameSizeInBytes/2;
      bufferLengthInBytes = bufferLengthInFrames * frameSizeInBytes;

      buffer = new byte[bufferLengthInBytes];

      //
//      if(originalClassLoader!=null)
//        Thread.currentThread().setContextClassLoader(originalClassLoader);
      //
    }
    catch(Exception ee){
      System.out.println(ee);
    }
    add(this);
  }

  void play(IO io){
    if(outputLine==null){ del(this); return; } // ??
    try{
      java.io.InputStream in=io.in;
      int i;
      int start, rest;
      outputLine.start();

      if(JEsd.streamPlayerPlugin!=null){
        StreamPlayerPlugin spp=(StreamPlayerPlugin)(JEsd.streamPlayerPlugin.newInstance());
        try{
          spp.play(outputLine, in);
          if(outputLine!=null){
            outputLine.drain();
            outputLine.stop();
            outputLine.close();
            outputLine.removeLineListener(this);
          }
          if(io!=null){ try{io.close();}catch(Exception eee){} }
          return;
	}
        catch(PluginException ee){
          byte[] foo=ee.getBuff();
          if(foo!=null)
  	    outputLine.write(foo, 0, foo.length);
	}
      }

      while(true){
	if(outputLine==null){ break; }
	i=in.read(buffer);
	if(i>0) outputLine.write(buffer, 0, i/*/frameSizeInBytes*/);
	else break;
      }
      if(outputLine!=null){
        outputLine.drain();
        outputLine.stop();
        outputLine.close();
        outputLine.removeLineListener(this);
      }
      if(io!=null){
        try{io.close();}catch(Exception ee){}
      }
    }
    catch(Exception e){}
    del(this);
  }

  void terminate(){
    if(outputLine!=null){
      SourceDataLine tmp=outputLine;
      outputLine=null;
      tmp.stop();
      tmp.close();
      tmp.removeLineListener(this);
    }
    del(this);
  }

  public void update(LineEvent event) {
    //System.out.println("update: "+event);
  }
//  public void meta(MetaEvent event) {
//    //System.out.println("meta: "+event);
//  }
}
