/*
 * Copyright 2007 Sun Microsystems, Inc.
 *
 * This file is part of jVoiceBridge.
 *
 * jVoiceBridge is free software: you can redistribute it and/or modify 
 * it under the terms of the GNU General Public License version 2 as 
 * published by the Free Software Foundation and distributed hereunder 
 * to you.
 *
 * jVoiceBridge 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 General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 *
 * Sun designates this particular file as subject to the "Classpath"
 * exception as provided by Sun in the License file that accompanied this 
 * code. 
 */

package com.sun.voip;

import java.io.IOException;

import java.net.DatagramPacket;

    /*
     * From RFC1889
     *
     * SR: Sender report RTCP packet
     * 
     *  0                   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|    RC   |   PT=SR=200   |             length            | header
     * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
     * |                         SSRC of sender                        |
     * +=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+
     * |              NTP timestamp, most significant word             | sender
     * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ info
     * |             NTP timestamp, least significant word             |
     * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
     * |                         RTP timestamp                         |
     * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
     * |                     sender's packet count                     |
     * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
     * |                      sender's octet count                     |
     * +=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+
     * |                 SSRC_1 (SSRC of first source)                 | report
     * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ block
     * | fraction lost |       cumulative number of packets lost       |   1
     * -+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
     * |           extended highest sequence number received           |
     * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
     * |                      interarrival jitter                      |
     * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
     * |                         last SR (LSR)                         |
     * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
     * |                   delay since last SR (DLSR)                  |
     * +=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+
     * |                 SSRC_2 (SSRC of second source)                | report
     * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ block
     * :                               ...                             :   2
     * +=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+
     * |                  profile-specific extensions                  |
     * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
     */

public class RtcpSenderPacket extends RtcpPacket {

    /*
     * This constructor is used for a packet which has been received.
     */
    public RtcpSenderPacket(DatagramPacket packet) {
	super(packet);
    }

    /*
     * This constructor is used to create a packet to send
     */
    public RtcpSenderPacket(int SSRC) {
	super(SSRC, true);
	setSSRC_1(SSRC);
    }

    public void setNTPTimestamp(long ts) {
	rtcpData[8] = (byte)  ((ts >> 56) & 0xff);
	rtcpData[9] = (byte)  ((ts >> 48) & 0xff);
	rtcpData[10] = (byte) ((ts >> 40) & 0xff);
	rtcpData[11] = (byte) ((ts >> 32) & 0xff);
	rtcpData[12] = (byte) ((ts >> 24) & 0xff);
	rtcpData[13] = (byte) ((ts >> 16) & 0xff);
	rtcpData[14] = (byte) ((ts >> 8) & 0xff);
	rtcpData[15] = (byte) (ts & 0xff);
    }

    public void setRTPTimestamp(int ts) {
	rtcpData[16] = (byte) ((ts >> 24) & 0xff);
	rtcpData[17] = (byte) ((ts >> 16) & 0xff);
	rtcpData[18] = (byte) ((ts >> 8) & 0xff);
	rtcpData[19] = (byte) (ts & 0xff);
    }

    public int getRTPTimestamp() {
        return ((((int)rtcpData[16]) << 24) & 0xff000000) |
               ((((int)rtcpData[17]) << 16) & 0x00ff0000) |
               ((((int)rtcpData[18]) << 8)  & 0x0000ff00) |
               (rtcpData[19] & 0xff);
    }

    public void setPacketCount(int packetCount) {
	rtcpData[20] = (byte) ((packetCount >> 24) & 0xff);
	rtcpData[21] = (byte) ((packetCount >> 16) & 0xff);
	rtcpData[22] = (byte) ((packetCount >> 8) & 0xff);
	rtcpData[23] = (byte) (packetCount & 0xff);
    }

    public int getPacketCount() {
        return ((((int)rtcpData[20]) << 24) & 0xff000000) |
               ((((int)rtcpData[21]) << 16) & 0x00ff0000) |
               ((((int)rtcpData[22]) << 8)  & 0x0000ff00) |
               (rtcpData[23] & 0xff);
    }

    public void setOctetCount(int octetCount) {
	rtcpData[24] = (byte) ((octetCount >> 24) & 0xff);
	rtcpData[25] = (byte) ((octetCount >> 16) & 0xff);
	rtcpData[26] = (byte) ((octetCount >> 8) & 0xff);
	rtcpData[27] = (byte) (octetCount >> 0xff);
    }

    public int getOctetCount() {
	return ((((int)rtcpData[24]) << 24) & 0xff000000) |
               ((((int)rtcpData[25]) << 16) & 0x00ff0000) |
	       ((((int)rtcpData[26]) << 8)  & 0x0000ff00) |
               (rtcpData[27] & 0xff);
    }

    public void setSSRC_1(int SSRC) {
	rtcpData[28] = (byte) ((SSRC >> 24) & 0xff);
	rtcpData[29] = (byte) ((SSRC >> 16) & 0xff);
	rtcpData[30] = (byte) ((SSRC >> 8) & 0xff);
	rtcpData[31] = (byte) (SSRC & 0xff);
    }

    public void setFractionLost(byte fractionLost) {
	rtcpData[32] = fractionLost;
    }

    public byte getFractionLost() {
	return rtcpData[32];
    }

    public void setCumulativeLost(int cumulativeLost) {
	rtcpData[33] = (byte) ((cumulativeLost >> 16) & 0xff);
	rtcpData[34] = (byte) ((cumulativeLost >> 8) & 0xff);
	rtcpData[35] = (byte) (cumulativeLost & 0xff);
    }

    public int getCumulativeLost() {
	int cumulativeLost = ((((int)rtcpData[33]) << 16) & 0x00ff0000) |
                             ((((int)rtcpData[34]) << 8) & 0x0000ff00) |
                             (rtcpData[35] & 0xff);

        if ((rtcpData[33] & 0x80) != 0) {
            cumulativeLost |= 0xff000000;       // it's negative
        }

	return cumulativeLost;
    }

    public void setHighestSeqReceived(int seq) {
	rtcpData[36] = (byte) ((seq >> 24) & 0xff);
	rtcpData[37] = (byte) ((seq >> 16) & 0xff);
	rtcpData[38] = (byte) ((seq >> 8) & 0xff);
	rtcpData[39] = (byte) (seq & 0xff);
    }

    public int getHighestSeqReceived() {
        return ((((int)rtcpData[36]) << 24) & 0xff000000) |
               ((((int)rtcpData[37]) << 16) & 0x00ff0000) |
               ((((int)rtcpData[38]) << 8)  & 0x0000ff00) |
               (rtcpData[39] & 0xff);
    }

    public void setInterArrivalJitter(int interArrivalJitter) {
	rtcpData[40] = (byte) ((interArrivalJitter >> 24) & 0xff);
	rtcpData[41] = (byte) ((interArrivalJitter >> 16) & 0xff);
	rtcpData[42] = (byte) ((interArrivalJitter >> 8) & 0xff);
	rtcpData[43] = (byte) (interArrivalJitter  & 0xff);
    }

    public int getInterArrivalJitter() {
        return ((((int)rtcpData[40]) << 24) & 0xff000000) |
               ((((int)rtcpData[41]) << 16) & 0x00ff0000) |
               ((((int)rtcpData[42]) << 8)  & 0x0000ff00) |
               (rtcpData[43] & 0xff);
    }

    public void setLSR(int LSR) {
	rtcpData[44] = (byte) ((LSR >> 24) & 0xff);
	rtcpData[45] = (byte) ((LSR >> 16) & 0xff);
	rtcpData[46] = (byte) ((LSR >> 8) & 0xff);
	rtcpData[47] = (byte) (LSR & 0xff);
    }

    public int getLSR() {
        return ((((int)rtcpData[44]) << 24) & 0xff000000) |
               ((((int)rtcpData[45]) << 16) & 0x00ff0000) |
               ((((int)rtcpData[46]) << 8)  & 0x0000ff00) |
               (rtcpData[47] & 0xff);

    }
    public void setDLSR(int DLSR) {
	rtcpData[48] = (byte) ((DLSR >> 24) & 0xff);
	rtcpData[49] = (byte) ((DLSR >> 16) & 0xff);
	rtcpData[50] = (byte) ((DLSR >> 8) & 0xff);
	rtcpData[51] = (byte) (DLSR & 0xff);
    }

    public void printReport() {
	if (Logger.logLevel >= Logger.LOG_INFO) {
            Logger.writeFile(" RTCP Sender report:  from " + from
                + ", RTP Timestamp " + Integer.toHexString(getRTPTimestamp())
                + ", packets " + getPacketCount()
                + ", octets " + getOctetCount()
                + ", fractionLost " + getFractionLost()
                + ", cumulativeLost " + getCumulativeLost()
                + ", highest seq "
                + Integer.toHexString(getHighestSeqReceived())
                + ", jitter " + getInterArrivalJitter());
	}
    }

}
