package nxm.audio.prim;

import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;

import javax.sound.sampled.AudioFormat;
import javax.sound.sampled.AudioInputStream;
import javax.sound.sampled.AudioSystem;
import javax.sound.sampled.DataLine;
import javax.sound.sampled.SourceDataLine;

import org.xiph.speex.spi.SpeexAudioFileReader;
import org.xiph.speex.spi.SpeexFormatConvertionProvider;

import nxm.sys.lib.FileName;
import nxm.sys.lib.MidasException;
import nxm.sys.lib.Primitive;

/** Simple audio player to play SPEEX audio

    @author David Zimmerman
    @since  NeXtMidas 2.1.0
*/
public class sinkspeexaudio extends Primitive {

  private FileInputStream speexFile;
  private AudioInputStream audiostr;
  private SourceDataLine audioLine;

  /** default constructor */
  public sinkspeexaudio () {}

  public int open () {

    FileName fn = MA.getFileName("IN");
    try {
// 2010-01-28 NTN: orig code to get input file (only looks under current directory)
//OLD      File spxfile = new File(MA.getCS("IN"));
      File spxfile = new File(fn.getFullName());
      speexFile    = new FileInputStream(spxfile);
    }
    catch (IOException e) {
      throw new MidasException("Could not get FileOutputStream for "+fn, e);
    }

    SpeexAudioFileReader spxReader = new SpeexAudioFileReader();
    AudioInputStream audioConv=null;
    try {
      audioConv = spxReader.getAudioInputStream(speexFile);
    }
    catch (Exception e) {
      throw new MidasException("Unsupported filetype: "+e, e);
    }

    SpeexFormatConvertionProvider convert = new SpeexFormatConvertionProvider();
    audiostr = convert.getAudioInputStream(AudioFormat.Encoding.PCM_SIGNED,audioConv);
    try {
      openAudio(audiostr.getFormat());
    }
    catch (Exception e) {
      M.printStackTrace(e);
      M.error(e);
    }

    return NORMAL;
  }

  public int process () {
    int bufsize=16,numbytes=0;
    byte buf[]=new byte[bufsize];
    try {
      while (-1<(numbytes=(audiostr.read(buf,0,bufsize)))) {
        audioLine.write(buf,0,numbytes);
        audioLine.start();
      }
    }
    catch (IOException e) {
      throw new MidasException("Error during write", e);
    }
    audioLine.drain();
    return FINISH;
  }

  public int close () {
    closeAudio();
    return NORMAL;
  }

  private void openAudio (AudioFormat audioFormat) {
    try {
      int frameSize = audioFormat.getFrameSize();
      if (verbose) M.info("Audio format = "+audioFormat+", FS="+frameSize);
      DataLine.Info lineInfo = new DataLine.Info(SourceDataLine.class,audioFormat);
      if (!AudioSystem.isLineSupported(lineInfo)) M.error("Audio "+lineInfo+" not supported");
      audioLine = (SourceDataLine)AudioSystem.getLine(lineInfo);
      audioLine.open(audioFormat);
    }
    catch (Exception e) {
      M.printStackTrace(e);
      throw new MidasException("Open failed", e);
    }
  }

  private void closeAudio () {
    audioLine.stop();
    audioLine.close();
  }
}
