/*
* Copyright (C) 2009 The Sipdroid Open Source Project
* Copyright (C) 2005 Luca Veltri - University of Parma - Italy
*
* This file is part of Sipdroid (http://www.sipdroid.org)
*
* Sipdroid is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 3 of the License, or
* (at your option) any later version.
*
* This source code 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 source code; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
package org.sipdroid.net;
import com.beem.project.beem.utils.Random;
/**
* RtpPacket implements a RTP packet.
*/
public class RtpPacket {
/* RTP packet buffer containing both the RTP header and payload */
byte[] packet;
/* RTP packet length */
int packet_len;
/* RTP header length */
// int header_len;
/** Gets the RTP packet */
public byte[] getPacket() {
return packet;
}
/** Gets the RTP packet length */
public int getLength() {
return packet_len;
}
/** Gets the RTP header length */
public int getHeaderLength() {
if (packet_len >= 12)
return 12 + 4 * getCscrCount();
else
return packet_len; // broken packet
}
/** Gets the RTP header length */
public int getPayloadLength() {
if (packet_len >= 12)
return packet_len - getHeaderLength();
else
return 0; // broken packet
}
/** Sets the RTP payload length */
public void setPayloadLength(int len) {
packet_len = getHeaderLength() + len;
}
// version (V): 2 bits
// padding (P): 1 bit
// extension (X): 1 bit
// CSRC count (CC): 4 bits
// marker (M): 1 bit
// payload type (PT): 7 bits
// sequence number: 16 bits
// timestamp: 32 bits
// SSRC: 32 bits
// CSRC list: 0 to 15 items, 32 bits each
/** Gets the version (V) */
public int getVersion() {
if (packet_len >= 12)
return (packet[0] >> 6 & 0x03);
else
return 0; // broken packet
}
/** Sets the version (V) */
public void setVersion(int v) {
if (packet_len >= 12)
packet[0] = (byte) ((packet[0] & 0x3F) | ((v & 0x03) << 6));
}
/** Whether has padding (P) */
public boolean hasPadding() {
if (packet_len >= 12)
return getBit(packet[0], 5);
else
return false; // broken packet
}
/** Set padding (P) */
public void setPadding(boolean p) {
if (packet_len >= 12)
packet[0] = setBit(p, packet[0], 5);
}
/** Whether has extension (X) */
public boolean hasExtension() {
if (packet_len >= 12)
return getBit(packet[0], 4);
else
return false; // broken packet
}
/** Set extension (X) */
public void setExtension(boolean x) {
if (packet_len >= 12)
packet[0] = setBit(x, packet[0], 4);
}
/** Gets the CSCR count (CC) */
public int getCscrCount() {
if (packet_len >= 12)
return (packet[0] & 0x0F);
else
return 0; // broken packet
}
/** Whether has marker (M) */
public boolean hasMarker() {
if (packet_len >= 12)
return getBit(packet[1], 7);
else
return false; // broken packet
}
/** Set marker (M) */
public void setMarker(boolean m) {
if (packet_len >= 12)
packet[1] = setBit(m, packet[1], 7);
}
/** Gets the payload type (PT) */
public int getPayloadType() {
if (packet_len >= 12)
return (packet[1] & 0x7F);
else
return -1; // broken packet
}
/** Sets the payload type (PT) */
public void setPayloadType(int pt) {
if (packet_len >= 12)
packet[1] = (byte) ((packet[1] & 0x80) | (pt & 0x7F));
}
/** Gets the sequence number */
public int getSequenceNumber() {
if (packet_len >= 12)
return getInt(packet, 2, 4);
else
return 0; // broken packet
}
/** Sets the sequence number */
public void setSequenceNumber(int sn) {
if (packet_len >= 12)
setInt(sn, packet, 2, 4);
}
/** Gets the timestamp */
public long getTimestamp() {
if (packet_len >= 12)
return getLong(packet, 4, 8);
else
return 0; // broken packet
}
/** Sets the timestamp */
public void setTimestamp(long timestamp) {
if (packet_len >= 12)
setLong(timestamp, packet, 4, 8);
}
/** Gets the SSCR */
public long getSscr() {
if (packet_len >= 12)
return getLong(packet, 8, 12);
else
return 0; // broken packet
}
/** Sets the SSCR */
public void setSscr(long ssrc) {
if (packet_len >= 12)
setLong(ssrc, packet, 8, 12);
}
/** Gets the CSCR list */
public long[] getCscrList() {
int cc = getCscrCount();
long[] cscr = new long[cc];
for (int i = 0; i < cc; i++)
cscr[i] = getLong(packet, 12 + 4 * i, 16 + 4 * i);
return cscr;
}
/** Sets the CSCR list */
public void setCscrList(long[] cscr) {
if (packet_len >= 12) {
int cc = cscr.length;
if (cc > 15)
cc = 15;
packet[0] = (byte) (((packet[0] >> 4) << 4) + cc);
cscr = new long[cc];
for (int i = 0; i < cc; i++)
setLong(cscr[i], packet, 12 + 4 * i, 16 + 4 * i);
// header_len=12+4*cc;
}
}
/** Sets the payload */
public void setPayload(byte[] payload, int len) {
if (packet_len >= 12) {
int header_len = getHeaderLength();
for (int i = 0; i < len; i++)
packet[header_len + i] = payload[i];
packet_len = header_len + len;
}
}
/** Gets the payload */
public byte[] getPayload() {
int header_len = getHeaderLength();
int len = packet_len - header_len;
byte[] payload = new byte[len];
for (int i = 0; i < len; i++)
payload[i] = packet[header_len + i];
return payload;
}
/** Creates a new RTP packet */
public RtpPacket(byte[] buffer, int packet_length) {
packet = buffer;
packet_len = packet_length;
if (packet_len < 12)
packet_len = 12;
init(0x0F);
}
/** init the RTP packet header (only PT) */
public void init(int ptype) {
init(ptype, Random.nextLong());
}
/** init the RTP packet header (PT and SSCR) */
public void init(int ptype, long sscr) {
init(ptype, Random.nextInt(), Random.nextLong(), sscr);
}
/** init the RTP packet header (PT, SQN, TimeStamp, SSCR) */
public void init(int ptype, int seqn, long timestamp, long sscr) {
setVersion(2);
setPayloadType(ptype);
setSequenceNumber(seqn);
setTimestamp(timestamp);
setSscr(sscr);
}
// *********************** Private and Static ***********************
/** Gets int value */
private static int getInt(byte b) {
return ((int) b + 256) % 256;
}
/** Gets long value */
private static long getLong(byte[] data, int begin, int end) {
long n = 0;
for (; begin < end; begin++) {
n <<= 8;
n += data[begin];
}
return n;
}
/** Sets long value */
private static void setLong(long n, byte[] data, int begin, int end) {
for (end--; end >= begin; end--) {
data[end] = (byte) (n % 256);
n >>= 8;
}
}
/** Gets Int value */
private static int getInt(byte[] data, int begin, int end) {
return (int) getLong(data, begin, end);
}
/** Sets Int value */
private static void setInt(int n, byte[] data, int begin, int end) {
setLong(n, data, begin, end);
}
/** Gets bit value */
private static boolean getBit(byte b, int bit) {
return (b >> bit) == 1;
}
/** Sets bit value */
private static byte setBit(boolean value, byte b, int bit) {
if (value)
return (byte) (b | (1 << bit));
else
return (byte) ((b | (1 << bit)) ^ (1 << bit));
}
}