src/jlibrtp/DataFrame.java
changeset 13 e684f11070d5
equal deleted inserted replaced
12:c9ff263c29ad 13:e684f11070d5
       
     1 /**
       
     2  * Java RTP Library (jlibrtp)
       
     3  * Copyright (C) 2006 Arne Kepp
       
     4  * 
       
     5  * This library is free software; you can redistribute it and/or
       
     6  * modify it under the terms of the GNU Lesser General Public
       
     7  * License as published by the Free Software Foundation; either
       
     8  * version 2.1 of the License, or (at your option) any later version.
       
     9  *
       
    10  * This library is distributed in the hope that it will be useful,
       
    11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
       
    12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
       
    13  * Lesser General Public License for more details.
       
    14  * 
       
    15  * You should have received a copy of the GNU Lesser General Public
       
    16  * License along with this library; if not, write to the Free Software
       
    17  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
       
    18  */
       
    19 package jlibrtp;
       
    20 
       
    21 
       
    22 /**
       
    23  * Data structure to hold a complete frame if frame reconstruction
       
    24  * is enabled, or the data from an individual packet if it is not
       
    25  * 
       
    26  * It also contains most of the data from the individual packets 
       
    27  * that it is based on.
       
    28  * 
       
    29  * @author Arne Kepp
       
    30  */
       
    31 public class DataFrame {
       
    32 	/** The share RTP timestamp */
       
    33 	private long rtpTimestamp;
       
    34 	/** The calculated UNIX timestamp, guessed after 2 Sender Reports */
       
    35 	private long timestamp = -1;
       
    36 	/** the SSRC from which this frame originated */
       
    37 	private long SSRC;
       
    38 	/** contributing CSRCs, only read from the first packet */
       
    39 	private long[] CSRCs;
       
    40 	/** RTP payload type */
       
    41 	private int payloadType;
       
    42 	/** The marks on individual packets, ordered */
       
    43 	private boolean[] marks;
       
    44 	/** Whether any packets were marked or not */
       
    45 	private boolean anyMarked = false;
       
    46 	/** Whether the frame contains the expected number of packets */
       
    47 	private int isComplete = 0;
       
    48 	//private int dataLength;
       
    49 	/** The data from the individual packets, ordered */
       
    50 	private byte[][] data;
       
    51 	/** The sequence numbers of the individual packets, ordered */
       
    52 	private int[] seqNum;
       
    53 	/** The total amount of data bytes in this frame */
       
    54 	private int totalLength = 0;
       
    55 	/** The last sequence number in this frame */
       
    56 	protected int lastSeqNum;
       
    57 	/** The first sequence number in this frame */
       
    58 	protected int firstSeqNum;
       
    59 	/** The number of packets expected for a complete frame */
       
    60 	protected int noPkts;
       
    61 	
       
    62 	/**
       
    63 	 * The usual way to construct a frame is by giving it a PktBufNode,
       
    64 	 * which contains links to all the other pkts that make it up.
       
    65 	 */
       
    66 	protected DataFrame(PktBufNode aBufNode, Participant p, int noPkts) {
       
    67 		if(RTPSession.rtpDebugLevel > 6) {
       
    68 			System.out.println("-> DataFrame(PktBufNode, noPkts = " + noPkts +")");
       
    69 		}
       
    70 		this.noPkts = noPkts;
       
    71 		RtpPkt aPkt = aBufNode.pkt;
       
    72 		int pktCount = aBufNode.pktCount;
       
    73 		firstSeqNum = aBufNode.pktCount;
       
    74 		
       
    75 		// All this data should be shared, so we just get it from the first one
       
    76 		this.rtpTimestamp = aBufNode.timeStamp;
       
    77 		SSRC = aPkt.getSsrc();
       
    78 		CSRCs = aPkt.getCsrcArray();
       
    79 		
       
    80 		// Check whether we can compute an NTPish timestamp? Requires two SR reports 
       
    81 		if(p.ntpGradient > 0) {
       
    82 			//System.out.print(Long.toString(p.ntpOffset)+" " 
       
    83 			timestamp =  p.ntpOffset + (long) (p.ntpGradient*(double)(this.rtpTimestamp-p.lastSRRtpTs));
       
    84 		}
       
    85 		
       
    86 		// Make data the right length
       
    87 		int payloadLength = aPkt.getPayloadLength();
       
    88 		//System.out.println("aBufNode.pktCount " + aBufNode.pktCount);
       
    89 		data = new byte[aBufNode.pktCount][payloadLength];
       
    90 		seqNum = new int[aBufNode.pktCount];
       
    91 		marks = new boolean[aBufNode.pktCount];
       
    92 		
       
    93 		// Concatenate the data of the packets
       
    94 		int i;
       
    95 		for(i=0; i< pktCount; i++) {
       
    96 			aPkt = aBufNode.pkt;
       
    97 			byte[] temp = aPkt.getPayload();
       
    98 			totalLength += temp.length;
       
    99 			if(temp.length == payloadLength) {
       
   100 				data[i] = temp;
       
   101 			} else if(temp.length < payloadLength){
       
   102 				System.arraycopy(temp, 0, data[i], 0, temp.length);
       
   103 			} else {
       
   104 				System.out.println("DataFrame() received node structure with increasing packet payload size.");
       
   105 			}
       
   106 			//System.out.println("i " + i + " seqNum[i] " + seqNum[i] + " aBufNode"  + aBufNode);
       
   107 			seqNum[i] = aBufNode.seqNum;
       
   108 			marks[i] = aBufNode.pkt.isMarked();
       
   109 			if(marks[i])
       
   110 				anyMarked = true;
       
   111 			
       
   112 			// Get next node
       
   113 			aBufNode = aBufNode.nextFrameNode;
       
   114 		}
       
   115 		
       
   116 		lastSeqNum = seqNum[i - 1];
       
   117 		
       
   118 		if(noPkts > 0) {
       
   119 			int seqDiff = firstSeqNum - lastSeqNum;
       
   120 			if(seqDiff < 0)
       
   121 				seqDiff = (Integer.MAX_VALUE - firstSeqNum)  + lastSeqNum;
       
   122 			if(seqDiff == pktCount && pktCount == noPkts)
       
   123 				isComplete = 1;
       
   124 		} else {
       
   125 			isComplete = -1;
       
   126 		}
       
   127 		
       
   128 		if(RTPSession.rtpDebugLevel > 6) {
       
   129 			System.out.println("<- DataFrame(PktBufNode, noPkt), data length: " + data.length);
       
   130 		}
       
   131 	}
       
   132 	
       
   133 	/**
       
   134 	 * Returns a two dimensial array where the first dimension represents individual
       
   135 	 * packets, from which the frame is made up, in order of increasing sequence number. 
       
   136 	 * These indeces can be matched to the sequence numbers returned by sequenceNumbers().
       
   137 	 * 
       
   138 	 * @return 2-dim array with raw data from packets
       
   139 	 */
       
   140 	public byte[][] getData() {
       
   141 		return this.data;
       
   142 	}
       
   143 	
       
   144 	/**
       
   145 	 * Returns a concatenated version of the data from getData()
       
   146 	 * It ignores missing sequence numbers, but then isComplete()
       
   147 	 * will return false provided that RTPAppIntf.frameSize()
       
   148 	 * provides a non-negative number for this payload type.
       
   149 	 * 
       
   150 	 * @return byte[] with all the data concatenated
       
   151 	 */
       
   152 	public byte[] getConcatenatedData() {
       
   153 		if(this.noPkts < 2) {
       
   154 			byte[] ret = new byte[this.totalLength];
       
   155 			int pos = 0;
       
   156 		
       
   157 			for(int i=0; i<data.length; i++) {
       
   158 				int length = data[i].length;
       
   159 				
       
   160 				// Last packet may be shorter
       
   161 				if(pos + length > totalLength) 
       
   162 					length = totalLength - pos;
       
   163 				
       
   164 				System.arraycopy(data[i], 0, ret, pos, length);
       
   165 				pos += data[i].length;
       
   166 			}
       
   167 			return ret;
       
   168 		} else {
       
   169 			return data[0];
       
   170 		}
       
   171 	}
       
   172 	
       
   173 	/**
       
   174 	 * If two SR packet have been received jlibrtp will attempt to calculate 
       
   175 	 * the local UNIX timestamp (in milliseconds) of all packets received.
       
   176 	 * 
       
   177 	 * This value should ideally correspond to the local time when the 
       
   178 	 * SSRC sent the packet. Note that the source may not be reliable.
       
   179 	 * 
       
   180 	 * Returns -1 if less than two SRs have been received
       
   181 	 * 
       
   182 	 * @return the UNIX timestamp, similar to System.currentTimeMillis() or -1;
       
   183 	 */
       
   184 	public long timestamp() {
       
   185 		return this.timestamp;
       
   186 		
       
   187 	}
       
   188 	
       
   189 	/**
       
   190 	 * Returns the RTP timestamp of all the packets in the frame.
       
   191 	 * 
       
   192 	 * @return unmodified RTP timestamp
       
   193 	 */
       
   194 	public long rtpTimestamp() {
       
   195 		return this.rtpTimestamp;
       
   196 	}
       
   197 	
       
   198 	/**
       
   199 	 * Returns the payload type of the packets
       
   200 	 * 
       
   201 	 * @return the payload type of the packets
       
   202 	 */
       
   203 	public int payloadType() {
       
   204 		return this.payloadType;
       
   205 	}
       
   206 
       
   207 	/**
       
   208 	 * Returns an array whose values, for the same index, correpond to the 
       
   209 	 * sequence number of the packet from which the data came.
       
   210 	 * 
       
   211 	 * This information can be valuable in conjunction with getData(), 
       
   212 	 * to identify what parts of a frame are missing.
       
   213 	 * 
       
   214 	 * @return array with sequence numbers
       
   215 	 */
       
   216 	public int[] sequenceNumbers() {
       
   217 		return seqNum;
       
   218 	}
       
   219 	
       
   220 	/**
       
   221 	 * Returns an array whose values, for the same index, correpond to 
       
   222 	 * whether the data was marked or not. 
       
   223 	 * 
       
   224 	 * This information can be valuable in conjunction with getData().
       
   225 	 * 
       
   226 	 * @return array of booleans
       
   227 	 */
       
   228 	public boolean[] marks() {
       
   229 		return this.marks;
       
   230 	}
       
   231 	
       
   232 	/**
       
   233 	 * Returns true if any packet in the frame was marked.
       
   234 	 * 
       
   235 	 * This function should be used if all your frames fit
       
   236 	 * into single packets.
       
   237 	 * 
       
   238 	 * @return true if any packet was marked, false otherwise
       
   239 	 */
       
   240 	public boolean marked() {
       
   241 		return this.anyMarked;
       
   242 	}
       
   243 	
       
   244 	/**
       
   245 	 * The SSRC associated with this frame.
       
   246 	 * 
       
   247 	 * @return the ssrc that created this frame
       
   248 	 */
       
   249 	public long ssrc() {
       
   250 		return this.SSRC;
       
   251 	}
       
   252 	
       
   253 	/**
       
   254 	 * The SSRCs that contributed to this frame
       
   255 	 * 
       
   256 	 * @return an array of contributing SSRCs, or null
       
   257 	 */
       
   258 	public long[] csrcs() {
       
   259 		return this.CSRCs;
       
   260 	}
       
   261 	
       
   262 	/**
       
   263 	 * Checks whether the difference in sequence numbers corresponds
       
   264 	 * to the number of packets received for the current timestamp,
       
   265 	 * and whether this value corresponds to the expected number of
       
   266 	 * packets.
       
   267 	 * 
       
   268 	 * @return true if the right number of packets make up the frame
       
   269 	 */
       
   270 	public int complete() {
       
   271 		return this.isComplete;
       
   272 	}
       
   273 }