diff -r 537ddd8aa407 -r 2036ebfaccda src/jlibrtp/DataFrame.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/jlibrtp/DataFrame.java Fri Nov 20 19:29:42 2009 +0100 @@ -0,0 +1,295 @@ +/** + * Java RTP Library (jlibrtp) + * Copyright (C) 2006 Arne Kepp + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ +package jlibrtp; + +import org.sipdroid.net.tools.DatagramPool; +import org.sipdroid.net.tools.PktBufNodePool; +import org.sipdroid.net.tools.RtpPktPool; + +/** + * Data structure to hold a complete frame if frame reconstruction is enabled, + * or the data from an individual packet if it is not + * + * It also contains most of the data from the individual packets that it is + * based on. + * + * @author Arne Kepp + */ +public class DataFrame { + /** The share RTP timestamp */ + private long rtpTimestamp; + /** The calculated UNIX timestamp, guessed after 2 Sender Reports */ + private long timestamp = -1; + /** the SSRC from which this frame originated */ + private long SSRC; + /** contributing CSRCs, only read from the first packet */ + private long[] CSRCs; + /** RTP payload type */ + private int payloadType; + /** The marks on individual packets, ordered */ + //private boolean[] marks; + /** Whether any packets were marked or not */ + private boolean anyMarked = false; + /** Whether the frame contains the expected number of packets */ + private int isComplete = 0; + // private int dataLength; + /** The data from the individual packets, ordered */ + //private byte[][] data; + /** The sequence numbers of the individual packets, ordered */ + //private int[] seqNum; + /** The total amount of data bytes in this frame */ + private int totalLength = 0; + /** The last sequence number in this frame */ + protected int lastSeqNum; + /** The first sequence number in this frame */ + protected int firstSeqNum; + /** The number of packets expected for a complete frame */ + protected int noPkts; + private RtpPkt[] pkts = new RtpPkt[5]; + + /** + * The usual way to construct a frame is by giving it a PktBufNode, which + * contains links to all the other pkts that make it up. + */ + protected DataFrame(PktBufNode aBufNode, Participant p, int noPkts) { + initDataFrame(aBufNode, p, noPkts); + } + + protected void initDataFrame(PktBufNode aBufNode, Participant p, int noPkts) { + if (RTPSession.rtpDebugLevel > 6) { + System.out.println("-> DataFrame(PktBufNode, noPkts = " + noPkts + + ")"); + } + this.noPkts = noPkts; + RtpPkt aPkt = aBufNode.pkt; + int pktCount = aBufNode.pktCount; + firstSeqNum = aBufNode.pktCount; + PktBufNode tempNode; + + // All this data should be shared, so we just get it from the first one + this.rtpTimestamp = aBufNode.timeStamp; + SSRC = aPkt.getSsrc(); + CSRCs = aPkt.getCsrcArray(); + + // Check whether we can compute an NTPish timestamp? Requires two SR + // reports + if (p.ntpGradient > 0) { + // System.out.print(Long.toString(p.ntpOffset)+" " + timestamp = p.ntpOffset + + (long) (p.ntpGradient * (double) (this.rtpTimestamp - p.lastSRRtpTs)); + } + + // Make data the right length + int payloadLength = aPkt.getPayloadLength(); + //seqNum = new int[aBufNode.pktCount]; + //marks = new boolean[aBufNode.pktCount]; + if (pktCount > 5) { + System.out.println("PKT COUNT TOO HIGH " + pktCount); + } + // Concatenate the data of the packets + int i; + for (i = 0; i < pktCount; i++) { + aPkt = aBufNode.pkt; + pkts[i] = aPkt; + // System.out.println("i " + i + " seqNum[i] " + seqNum[i] + + // " aBufNode" + aBufNode); + //seqNum[i] = aBufNode.seqNum; + if (aBufNode.pkt.isMarked()) + anyMarked = true; + + // Get next node + tempNode = aBufNode; + aBufNode = aBufNode.nextFrameNode; + PktBufNodePool.getInstance().returnBufNode(tempNode); + lastSeqNum = aPkt.getSeqNumber(); + } + + if (noPkts > 0) { + int seqDiff = firstSeqNum - lastSeqNum; + if (seqDiff < 0) + seqDiff = (Integer.MAX_VALUE - firstSeqNum) + lastSeqNum; + if (seqDiff == pktCount && pktCount == noPkts) + isComplete = 1; + } else { + isComplete = -1; + } + + if (RTPSession.rtpDebugLevel > 6) { + System.out.println("<- DataFrame(PktBufNode, noPkt), data length: " + + pkts.length); + } + } + + public DataFrame(){ + } + + /** + * Returns a two dimensial array where the first dimension represents + * individual packets, from which the frame is made up, in order of + * increasing sequence number. These indeces can be matched to the sequence + * numbers returned by sequenceNumbers(). + * + * @return 2-dim array with raw data from packets + */ + /*public byte[][] getData() { + return this.data; + }*/ + + public RtpPkt[] getPkt(){ + return this.pkts ; + } + + /** + * Returns a concatenated version of the data from getData() It ignores + * missing sequence numbers, but then isComplete() will return false + * provided that RTPAppIntf.frameSize() provides a non-negative number for + * this payload type. + * + * @return byte[] with all the data concatenated + */ + /*public byte[] getConcatenatedData() { + if (this.noPkts < 2) { + byte[] ret = new byte[this.totalLength]; + int pos = 0; + + for (int i = 0; i < data.length; i++) { + int length = data[i].length; + + // Last packet may be shorter + if (pos + length > totalLength) + length = totalLength - pos; + + System.arraycopy(data[i], 0, ret, pos, length); + pos += data[i].length; + } + return ret; + } else { + return data[0]; + } + }*/ + + /** + * If two SR packet have been received jlibrtp will attempt to calculate the + * local UNIX timestamp (in milliseconds) of all packets received. + * + * This value should ideally correspond to the local time when the SSRC sent + * the packet. Note that the source may not be reliable. + * + * Returns -1 if less than two SRs have been received + * + * @return the UNIX timestamp, similar to System.currentTimeMillis() or -1; + */ + public long timestamp() { + return this.timestamp; + + } + + /** + * Returns the RTP timestamp of all the packets in the frame. + * + * @return unmodified RTP timestamp + */ + public long rtpTimestamp() { + return this.rtpTimestamp; + } + + /** + * Returns the payload type of the packets + * + * @return the payload type of the packets + */ + public int payloadType() { + return this.payloadType; + } + + /** + * Returns an array whose values, for the same index, correpond to the + * sequence number of the packet from which the data came. + * + * This information can be valuable in conjunction with getData(), to + * identify what parts of a frame are missing. + * + * @return array with sequence numbers + */ + /*public int[] sequenceNumbers() { + return seqNum; + }*/ + + /** + * Returns an array whose values, for the same index, correpond to whether + * the data was marked or not. + * + * This information can be valuable in conjunction with getData(). + * + * @return array of booleans + */ + /*public boolean[] marks() { + return this.marks; + }*/ + + /** + * Returns true if any packet in the frame was marked. + * + * This function should be used if all your frames fit into single packets. + * + * @return true if any packet was marked, false otherwise + */ + public boolean marked() { + return this.anyMarked; + } + + /** + * The SSRC associated with this frame. + * + * @return the ssrc that created this frame + */ + public long ssrc() { + return this.SSRC; + } + + /** + * The SSRCs that contributed to this frame + * + * @return an array of contributing SSRCs, or null + */ + public long[] csrcs() { + return this.CSRCs; + } + + /** + * Checks whether the difference in sequence numbers corresponds to the + * number of packets received for the current timestamp, and whether this + * value corresponds to the expected number of packets. + * + * @return true if the right number of packets make up the frame + */ + public int complete() { + return this.isComplete; + } + + public void release() { + for(RtpPkt pkt : this.pkts) { + if (pkt != null) { + if (pkt.getDatagramPacket() != null) + DatagramPool.getInstance().returnPacket(pkt.getDatagramPacket()); + RtpPktPool.getInstance().returnPkt(pkt); + } + } + } +}