/* ***************************************************************************+
 * ITX package (cnrg.itx) for telephony application programming.              *
 * Copyright (c) 1999  Cornell University, Ithaca NY.                         *
 * A copy of the license is distributed with this package.  Look in the docs  *
 * directory, filename GPL.  Contact information: bergmark@cs.cornell.edu     *
 ******************************************************************************/


package cnrg.itx.datax.devices;

/**
 * Class defining the RFC 1889 implementation of an RTP header.
 *                      1                   2                   3
 *  0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
 * |V=2|P|X|  CC   |M|     PT      |       sequence number         |
 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
 * |                           timestamp                           |
 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
 * |           synchronization source (SSRC) identifier            |
 * +=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+
 * |            contributing source (CSRC) identifiers             |
 * |                             ....                              |
 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
 */
class RTPHeader
{
	/**
	 * Constants defining some of the standard media formats for the RTP
	 * payload types. Not all have been implemented but the complete list
	 * is as follows:
	 * Payload    encoding      audio/video    clock rate    channels
     * Type       name          (A/V)          (Hz)          (audio)
     * _______________________________________________________________
     * 0          PCMU          A              8000          1     [RFC1890]
     * 1          1016          A              8000          1     [RFC1890]
     * 2          G721          A              8000          1     [RFC1890]
     * 3          GSM           A              8000          1     [RFC1890]
     * 4          G723          A              8000          1       [Kumar]
     * 5          DVI4          A              8000          1     [RFC1890]
     * 6          DVI4          A              16000         1     [RFC1890]
     * 7          LPC           A              8000          1     [RFC1890]
     * 8          PCMA          A              8000          1     [RFC1890]
     * 9          G722          A              8000          1     [RFC1890]
     * 10         L16           A              44100         2     [RFC1890]
     * 11         L16           A              44100         1     [RFC1890]
     * 12         reserved      A
     * 13         reserved      A
     * 14         MPA           A              90000         ?[RFC1890,2250]
     * 15         G728          A              8000          1     [RFC1890]
     * 16         DVI4          A             11025          1       [DiPol]
     * 17         DVI4          A             22050          1       [DiPol]
     * 18--22     unassigned    A
     * 23         reserved      A
     * 24         reserved      V
     * 25         CelB          V              90000               [RFC2029]
     * 26         JPEG          V              90000               [RFC2435]
     * 27         reserved      V
     * 28         nv            V              90000               [RFC1890]
     * 29         reserved      V
     * 30         reserved      V
     * 31         H261          V              90000               [RFC2032]
     * 32         MPV           V              90000               [RFC2250]
     * 33         MP2T          AV             90000               [RFC2250]
     * 34         H263          V              90000                   [Zhu]
     * 35--71     unassigned    ?
     * 72--76     reserved for RTCP conflict avoidance             [RFC1889]
     * 77--95     unassigned    ?
     * 96--127    dynamic       ?                                  [RFC1890]
     * 
     * The constants should be defined as given below for some of the payload
     * types.
	 */
	final public static int PCMU_8000 = 0;
	final public static int G721_8000 = 2;
	final public static int PCMA_8000 = 8;

	/**
	 * Attribute for the RTP packet version.
	 */
	private int version = 2;
	
	/**
	 * Padding flag.
	 */
	private int padding = 0;
	
	/**
	 * Packet header extension flag.
	 */
	private int packetExtension = 0;
	
	/**
	 * Number of contributing sources.
	 */
	private int numCSources = 0;
	
	/**
	 * Marker bit.
	 */
	private int marker = 0;
	
	/**
	 * Payload type.
	 */
	private int payloadType;
	
	/**
	 * Packet sequence number.
	 */
	private short sequence;
	
	/**
	 * Packet timestamp.
	 */
	private int timeStamp;
	
	/**
	 * Synchronization source.
	 */
	private int ssrc;
	
	/**
	 * Contributing source identifiers.
	 */
	private int csrc[];

	/**
	 * Constructor for an RTP header taking the 32 bit source identifier and
	 * the payload type.
	 * @param ssrc the 32 bit source ID
	 * @param payloadType the kind of real time data contained in the packet
	 */
	public RTPHeader(int ssrc, int payloadType)
	{
		this.ssrc = ssrc;
		this.payloadType = payloadType;
	}
	
	/**
	 * Constructor to extract the RTP header from a RTP byte array.
	 * @param rtpData the byte array of RTP data
	 */
	public RTPHeader(byte[] rtpData)
	{
		// Decode the bytes in the RTP byte array.
		
		// First two bits from the left is the version number
		version = rtpData[0] & 0x000000C0;
		
		// Third bit from the left is the padding
		padding = rtpData[0] & 0x00000020;
		
		// Fourth bit from the left is the packet extension
		packetExtension = rtpData[0] & 0x00000010;
		
		// Last four bits in the first byte are the number of sources
		numCSources = rtpData[0] & 0x0000000F;

		// First bit in the second byte is the marker bit
		marker = rtpData[1] & 0x00000080;
		
		// Next 7 bits are for the payload type
		payloadType = rtpData[1] & 0x0000007F;

		// Get the packet sequence number from the 3rd and 4th byte
		sequence = getShort(rtpData, 2);

		// Get the timestamp from the 5-8th bytes
		timeStamp = getInt(rtpData, 4);
		
		// Get the ssrc number from the 9-12th bytes
		ssrc = getInt(rtpData, 8);

		// Time to get the contributing source identifiers if there are any
		if(numCSources > 0)
		{
			csrc = new int[numCSources];
		
			for (int i=0; i<numCSources; i++)
				csrc[i] = getInt(rtpData, 12 + i*4);
		}
	}
	
	/**
	 * Method to copy the RTP header into the byte array provided.
	 * @param packet the byte array to copy the header into
	 */
	public void copyHeader(byte[] packet)
	{
		// First byte has the version, padding, extension and number of sources
		packet[0] = (byte)(version << 6 |
						   padding << 5 |
						   packetExtension << 4 |
						   numCSources);
		
		// Copy the marker and the payload type
		packet[1] = (byte)(marker << 7 |
						   payloadType);

		// Copy the sequence number, timestamp and the number of sources
		setShort(packet, 2, sequence);
		setInt(packet, 4, timeStamp);
		setInt(packet, 8, ssrc);

		// Copy all the source IDs if there are any
		if(numCSources > 0)
		{
			for (int i=0; i<numCSources; i++)
				setInt(packet, 12 + i*4, csrc[i]);
		}
	}
	
	/**
	 * Accessor for the current size of the header in bytes. The size 
	 * depends on the version and the amount of csrc identifiers.
	 * @return int the size of the header in bytes
	 */
	public int getHeaderSize()
	{
		// The size is 12 bytes for the standard header and 4 bytes for
		// each contributing source.
		return (12 + (4*numCSources));
	}

	/**
	 * Accessor to get the version of the RTP header.
	 * @return int the version for the RTP header
	 */
	public int getVersion()
	{
		// We use version 2 of the protocol
		return version;
	}
	
	/**
	 * Accessor for the current state of padding.
	 * @return int the current state of the padding
	 */
	public int getPadding()
	{
		return padding;
	}

	/**
	 * Accessor to get the packet extension. This is the current state of 
	 * extension. If the extension bit is set, the fixed header is followed 
	 * by exactly one header extension as defined rfc 1889 Section 5.3.1.
	 * @return int the value of the the extension bit
	 */
	public int getExtension()
	{
		return packetExtension;
	}

	/**
	 * Accessor to get the packet marker. This is the current state of marker. 
	 * The meaning of this bit should be interpreted by the protocol.
	 * Could for example mean silence will follow.
	 * @return int the state of the packet marker
	 */
	public int getMarker()
	{
		return marker;
	}

	/**
	 * Accessor to get the packet sequence number. This is used to detect gaps
	 * in the packets.
	 * @return int the sequence number of the packet.
	 */
	public int getSequence()
	{
		return (int) (0xffff & sequence);
	}

	/**
	 * Mutator to set the sequence number of the packet.
	 * @param sequence the packet sequence number
	 */
	public void setSequence(short sequence)
	{
		this.sequence = sequence;
	}

	/**
	 * Accessor to get the current timestamp of the packet. This is used to 
	 * know which rtp packets belong together. Mainly used for video where 
	 * multiple packets can have the same timestamp.
	 * @return int the value of the packet timestamp
	 */
	public int getTimeStamp()
	{
		return timeStamp;
	}

	/**
	 * Mutator to set the packet timestamp.
	 * @param timeStamp the timestamp of the packet
	 */
	public void setTimeStamp(int timeStamp)
	{
		this.timeStamp = timeStamp;
	}
	
	/**
	 * Accessor to get the list of contributing sources. The rtp packet can
	 * contain between 0 and 15 sources	including the zero and fifteen.
	 * @return int[] the array of source IDs
	 */
	public int[] getCSRC()
	{
		return csrc;
	}

	/**
	 * Accessor to get the current synchronization source. This should 
	 * be an unique identifier as we could listen to multiple sources.
	 * @return int the synchronization source number
	 */
	public int getSSRC()
	{
		return ssrc;
	}

	/**
	 * Accessor for the current payloadtype. This is essentially the current 
	 * encoding used. For a defined list see RFC1890, page 14.
	 * @return int the current payload type
	 */
	public int getPayLoadType()
	{
		return payloadType;
	}

	/**
	 * Method to put an integer(32 bits) value in the header.
	 * @param packet the byte array to put the value in
	 * @param pos the position at which the bytes need to be put
	 * @param value the integer value to be put
	 */
	private void setInt(byte[] packet, int pos, int value)
	{
		packet[pos+0] = (byte)(value >> 24);
		packet[pos+1] = (byte)(value >> 16);
		packet[pos+2] = (byte)(value >> 8);
		packet[pos+3] = (byte)(value);
	}

	/**
	 * Method to get an integer(32 bit) value from a position in a byte array.
	 * @param packet the byte array to get the value from
	 * @param pos the position from which to get the 32 bit value
	 */
	private int getInt(byte[] packet, int pos)
	{
		return (((int)(packet[pos+0]) << 24) & 0xff000000) + 
		       (((int)(packet[pos+1]) << 16) & 0x00ff0000) + 
		       (((int)(packet[pos+2]) <<  8) & 0x0000ff00) + 
		       (((int)(packet[pos+3]) <<  0) & 0x000000ff);
	}

	/**
	 * Method to set a short(16 bit) value in a byte array.
	 * @param packet the byte array to put the value in
	 * @param pos the position at which the bytes need to be put
	 * @param value the short value to be put
	 */
	private void setShort(byte[] packet, int pos, short value)
	{
		packet[pos+0] = (byte)(value >> 8);
		packet[pos+1] = (byte)(value);
	}

	/**
	 * Method to get a short(16 bit) value from a position in a byte array.
	 * @param packet the byte array to get the value from
	 * @param pos the position from which to get the 16 bit value
	 */
	private short getShort(byte[] packet, int pos)
	{
		return (short)((((int)(packet[pos+0]) << 8) & 0x0000ff00) +
					   (((int)(packet[pos+1]) << 0) & 0x000000ff));
	}
}
