/*
 * @(#)JavaEncoder.java	1.13 02/08/21
 *
 * Copyright (c) 1996-2002 Sun Microsystems, Inc.  All rights reserved.
 */

package com.ibm.media.codec.audio.gsm;

import javax.media.*;
import javax.media.format.*;
import javax.media.format.*;
import com.sun.media.*;

/**
 * RTP GSM encoder plugin wrapper, which uses Java methods to do the encoding.
 * @author Shay Ben-David bendavid@haifa.vnet.ibm.com
 */
public class JavaEncoder extends com.ibm.media.codec.audio.BufferedEncoder {

     ////////////////////////////////////////////////////////////////////////////
    // Variables

   /** <FONT COLOR="#FF0000">
    *  Licensed Materials - Property of IBM                         <br><br>
    *  "Restricted Materials of IBM"                                <br><br>
    *  5648-B81                                                     <br><br>
    *  (c) Copyright IBM Corporation 1997,1999 All Rights Reserved  <br><br>
    *  US Government Users Restricted Rights - Use, duplication or
    *  disclosure restricted by GSA ADP Schedule Contract with
    *  IBM Corporation.</FONT>
    *
    **/
    public static final String a_copyright_notice="(c) Copyright IBM Corporation 1997,1999.";

  protected GsmEncoder encoder;

  // the default RTP packet size for the outputformat in units of samples.
  // for gsm, 160 audio samples are compressed to 33 bytes. We want the
  //default millisec perpacket to be 20ms --> 160 audio samples --> 33 octets.
  private int sample_count = 160;
  
    private long currentSeq = (long) (System.currentTimeMillis() * Math.random
());

    // current timestamp on RTP format packets.
    //private long timestamp = (long) (System.currentTimeMillis() * Math.random());
    private long timestamp = 0L;

  // the buffer used by the RTP packetization method
  byte[] pendingBuffer = null;
  
     ////////////////////////////////////////////////////////////////////////////
    // Methods

    public JavaEncoder() {
       	supportedInputFormats = new AudioFormat[] {
	                                new AudioFormat(AudioFormat.LINEAR,
					        Format.NOT_SPECIFIED,
						16,
						1,
						AudioFormat.LITTLE_ENDIAN,
						AudioFormat.SIGNED,
                                                Format.NOT_SPECIFIED,
                                                Format.NOT_SPECIFIED,
                                                Format.byteArray) };

	defaultOutputFormats  = new AudioFormat[] {
	    new AudioFormat(AudioFormat.GSM) /*,
	    new AudioFormat(AudioFormat.GSM_RTP)*/};

        PLUGIN_NAME="GSM Encoder";
        historySize = 320;
	pendingFrames = 0;
	// for RTP, set default packetsize to 160 audiosamples for a
	// default ms/packet of 20ms. This works out to 33 octets.
	//note if this value changes in setPacketSize(), sample count
	// needs to be updated as well.
	packetSize = 33;

    }

    protected  Format[] getMatchingOutputFormats(Format in) {

        AudioFormat af =(AudioFormat) in;

        supportedOutputFormats = new AudioFormat[] {
                new AudioFormat(
                    AudioFormat.GSM,
                    af.getSampleRate(),
                    16,
                    af.getChannels(),
                    Format.NOT_SPECIFIED,
                    Format.NOT_SPECIFIED,
                    264,
                    Format.NOT_SPECIFIED,
                    Format.byteArray
                )/*,

                new AudioFormat(
                    AudioFormat.GSM_RTP,
		    af.getSampleRate(),
                    Format.NOT_SPECIFIED,
		    af.getChannels(),
                    Format.NOT_SPECIFIED,
                    Format.NOT_SPECIFIED,
                    264,
                    Format.NOT_SPECIFIED,
                    Format.byteArray
                )  */

        };
        return  supportedOutputFormats;
    }

    public void open() throws ResourceUnavailableException{
        encoder=new GsmVadEncoder();
        encoder.gsm_encoder_reset();
    }

    public void codecReset() {
        encoder.gsm_encoder_reset();
    }


    public void close() {
        encoder=null;
    }

  public int process(Buffer inputBuffer, Buffer outputBuffer){
    // let the buffered encoder process the input buffer. this will
    // encode the data for us.Only RTP packetization will be desired
    // at this time.
    int retVal = super.process(inputBuffer, outputBuffer);
    
    // if the output format is not RTP, just return the from here.
    if (!outputFormat.getEncoding().equals(AudioFormat.GSM_RTP))
      return retVal;

    // if it is RTP, packetize the data.
    if (outputFormat.getEncoding().equals(AudioFormat.GSM_RTP)){

      // before we proceed for packetization, check for failure in
      // encoding and EOM
      if (retVal == BUFFER_PROCESSED_FAILED)
	return retVal;
      if (isEOM(inputBuffer) ) {
	propagateEOM(outputBuffer);
	return BUFFER_PROCESSED_OK;
      }

      // Now, if there are no pending frames, we are beginning
      // packetization of a new buffer.get a handle over the buffer to
      // be packetized
      if (pendingFrames == 0)
	pendingBuffer = (byte[])outputBuffer.getData();

      // start packetizing one frame at a time (160 samples)
      // the size of outputdata depends on the packet size set.
      byte[] outData = new byte[packetSize];
      outputBuffer.setData(outData);
      updateOutput(outputBuffer, outputFormat,packetSize, 0);
      outputBuffer.setSequenceNumber(currentSeq++);
      outputBuffer.setTimeStamp(timestamp);
      timestamp+=sample_count;

      System.arraycopy(pendingBuffer,
		       regions[pendingFrames],
		       outData,
		       0,
		       packetSize);

      if (pendingFrames + 1== frameNumber[0]){
	pendingFrames = 0;
	pendingBuffer = null;
	return BUFFER_PROCESSED_OK;
      }else
	pendingFrames++;

      return INPUT_BUFFER_NOT_CONSUMED;

    }//end of GSM_RTP

    return retVal;
  }

  protected int calculateOutputSize(int inputSize) {
    return calculateFramesNumber(inputSize) * 33 ;
  }

  protected int calculateFramesNumber(int inputSize) {
    return inputSize / 320;
  }



    protected boolean codecProcess(byte[] inpData,int readPtr,
                                    byte[] outData,int writePtr,
  			            int inpLength,
				    int[]  readBytes,int[] writeBytes,
                                    int[]  frameNumber,
				    int[] regions,int[] regionsTypes) {

        int inCount = 0;
        int outCount = 0;
        int channels=inputFormat.getChannels();
        boolean isStereo = ( channels == 2);

        int frames = inpLength/(320);

        regions[0]=writePtr;

        for (int frameCounter = 0; frameCounter<frames ; frameCounter++) {
              encoder.gsm_encode_frame(inpData, readPtr , outData,writePtr);
              readPtr += 320;
              inCount += 320;

              outCount += 33;
              writePtr += 33;

	      //regions [frameCounter+1]= outCount + writePtr;
	      regions [frameCounter +1] = writePtr;
              regionsTypes[frameCounter  ]= 0;

	      //System.out.println(inCount+" "+outCount+" "+inpLength);
        }

        readBytes [0]=inCount;
        writeBytes[0]=outCount;
        frameNumber[0]=frames;

        return true;
    }




}



