src/jlibrtp/RtpPkt.java
changeset 214 2bf440c54ca5
parent 213 9bdff6cbd120
child 215 5db64229be69
equal deleted inserted replaced
213:9bdff6cbd120 214:2bf440c54ca5
     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  * RtpPkt is the basic class for creating and parsing RTP packets.
       
    23  * 
       
    24  * There are two ways of instantiating an RtpPkt. One is for packets that you wish to send,
       
    25  * which requires that you provide basic information about the packet and a payload. Upon calling
       
    26  * encode() the fields of the structure are written into a bytebuffer, in the form that it would
       
    27  * sent across the network, excluding the UDP headers.
       
    28  * 
       
    29  * The other way is by passing a bytebuffer. The assumption is that this is a packet
       
    30  * that has been received from the network, excluding UDP headers, and the bytebuffer will
       
    31  * be parsed into the correct fields. 
       
    32  * 
       
    33  * The class keeps track of changes. Therefore, modifications are possible after calling encode(),
       
    34  * if necessary, the raw version of the packet will be regenerated on subsequent requests.
       
    35  * 
       
    36  * @author Arne Kepp
       
    37  */
       
    38 public class RtpPkt {
       
    39 	/** Whether the packet has been changed since encode() */
       
    40 	private boolean rawPktCurrent = false;
       
    41 	/** The version, always 2, 2 bits */
       
    42 	private int version = 2; 		//2 bits
       
    43 	/** Whether the packet is padded, 1 bit */
       
    44 	private int padding; 			//1 bit
       
    45 	/** Whether and extension is used, 1 bit */
       
    46 	private int extension = 0; 		//1 bit
       
    47 	/** Whether the packet is marked, 1 bit */
       
    48 	private int marker = 0;			//1 bit
       
    49 	/** What payload type is used, 7 bits */
       
    50 	private int payloadType;		//
       
    51 	/** The sequence number, taken from RTP Session, 16 bits */
       
    52 	private int seqNumber;			//16 bits
       
    53 	/** The RTP timestamp, 32bits */
       
    54 	private long timeStamp;			//32 bits
       
    55 	/** The SSRC of the packet sender, 32 bits*/
       
    56 	private long ssrc;				//32 bits
       
    57 	/** SSRCs of contributing sources, 32xn bits, n<16 */ 
       
    58 	private long[] csrcArray = null;//
       
    59 	
       
    60 	/** Contains the actual data (eventually) */
       
    61 	private byte[] rawPkt = null;
       
    62 	/** The actual data, without any RTP stuff */
       
    63 	private byte[] payload = null;
       
    64 
       
    65 	/**
       
    66 	 * Construct a packet-instance. The ByteBuffer required for UDP transmission can afterwards be obtained from getRawPkt(). If you need to set additional parameters, such as the marker bit or contributing sources, you should do so before calling getRawPkt;
       
    67 	 *
       
    68 	 * @param aTimeStamp RTP timestamp for data
       
    69 	 * @param syncSource the SSRC, usually taken from RTPSession
       
    70 	 * @param seqNum Sequency number
       
    71 	 * @param plt Type of payload
       
    72 	 * @param pl Payload, the actual data
       
    73 	 */
       
    74 	protected RtpPkt(long aTimeStamp, long syncSource, int seqNum, int plt, byte[] pl){
       
    75 		int test = 0;
       
    76 		test += setTimeStamp(aTimeStamp);
       
    77 		test += setSsrc(syncSource);
       
    78 		test += setSeqNumber(seqNum);
       
    79 		test += setPayloadType(plt);
       
    80 		test += setPayload(pl);
       
    81 		if(test != 0) {
       
    82 			System.out.println("RtpPkt() failed, check with checkPkt()");
       
    83 		}
       
    84 		rawPktCurrent = true;
       
    85 		if( RTPSession.rtpDebugLevel > 5) {
       
    86 			System.out.println("<--> RtpPkt(aTimeStamp, syncSource, seqNum, plt, pl)"); 
       
    87 		}
       
    88 	}
       
    89 	/**
       
    90 	 * Construct a packet-instance from an raw packet (believed to be RTP). The UDP-headers must be removed before invoking this method. Call checkPkt on the instance to verify that it was successfully parsed.
       
    91 	 *
       
    92 	 * @param aRawPkt The data-part of a UDP-packet believed to be RTP 
       
    93 	 * @param packetSize the number of valid octets in the packet, should be aRawPkt.length
       
    94 	 */
       
    95 	protected RtpPkt(byte[] aRawPkt, int packetSize){
       
    96 		if( RTPSession.rtpDebugLevel > 5) {
       
    97 			System.out.println("-> RtpPkt(aRawPkt)"); 
       
    98 		}
       
    99 		//Check size, need to have at least a complete header
       
   100 		if(aRawPkt == null) {
       
   101 			System.out.println("RtpPkt(byte[]) Packet null");
       
   102 		}
       
   103 		
       
   104 		int remOct = packetSize - 12;
       
   105 		if(remOct >= 0) {
       
   106 			rawPkt = aRawPkt;	//Store it
       
   107 			//Interrogate the packet
       
   108 			sliceFirstLine();
       
   109 			if(version == 2) {
       
   110 				sliceTimeStamp();
       
   111 				sliceSSRC();
       
   112 				if(remOct > 4 && getCsrcCount() > 0) {
       
   113 					sliceCSRCs();
       
   114 					remOct -= csrcArray.length * 4; //4 octets per CSRC
       
   115 				}
       
   116 				// TODO Extension
       
   117 				if(remOct > 0) {
       
   118 					slicePayload(remOct);
       
   119 				}
       
   120 			
       
   121 				//Sanity checks
       
   122 				checkPkt();
       
   123 		
       
   124 				//Mark the buffer as current
       
   125 				rawPktCurrent = true;
       
   126 			} else {
       
   127 				System.out.println("RtpPkt(byte[]) Packet is not version 2, giving up.");
       
   128 			}
       
   129 		} else {
       
   130 			System.out.println("RtpPkt(byte[]) Packet too small to be sliced");
       
   131 		}
       
   132 		rawPktCurrent = true;
       
   133 		if( RTPSession.rtpDebugLevel > 5) {
       
   134 			System.out.println("<- RtpPkt(aRawPkt)");
       
   135 		}
       
   136 	}
       
   137 	
       
   138 	/*********************************************************************************************************
       
   139 	 *                                                Reading stuff 
       
   140 	 *********************************************************************************************************/
       
   141 	protected int checkPkt() {
       
   142 		//TODO, check for version 2 etc
       
   143 		return 0;
       
   144 	}
       
   145 	protected int getHeaderLength() {
       
   146 		//TODO include extension
       
   147 		return 12 + 4*getCsrcCount();
       
   148 	}
       
   149 	protected int getPayloadLength() {
       
   150 		return payload.length;
       
   151 	}
       
   152 	//public int getPaddingLength() {
       
   153 	//	return lenPadding;
       
   154 	//}
       
   155 	protected int getVersion() {
       
   156 		return version;
       
   157 	}
       
   158 	//public boolean isPadded() {
       
   159 	//	if(lenPadding > 0) {
       
   160 	//		return true;
       
   161 	//	}else {
       
   162 	//		return false;
       
   163 	//	}
       
   164 	//}
       
   165 	//public int getHeaderExtension() {
       
   166 	//TODO
       
   167 	//}
       
   168 	protected boolean isMarked() {
       
   169 		return (marker != 0);
       
   170 	}
       
   171 	protected int getPayloadType() {
       
   172 		return payloadType;
       
   173 	}
       
   174 	
       
   175 	protected int getSeqNumber() {
       
   176 		return seqNumber;
       
   177 	}
       
   178 	protected long getTimeStamp() {
       
   179 		return timeStamp;
       
   180 	}
       
   181 	protected long getSsrc() {
       
   182 		return ssrc;
       
   183 	}
       
   184 	
       
   185 	protected int getCsrcCount() {
       
   186 		if(csrcArray != null) {
       
   187 			return csrcArray.length;
       
   188 		}else{
       
   189 			return 0;
       
   190 		}
       
   191 	}
       
   192 	protected long[] getCsrcArray() {
       
   193 		return csrcArray;
       
   194 	}
       
   195 
       
   196 	/** 
       
   197 	 *  Encodes the a
       
   198 	 */
       
   199 	protected byte[] encode() {
       
   200 		if(! rawPktCurrent || rawPkt == null) {
       
   201 			writePkt();
       
   202 		} 
       
   203 		return rawPkt;
       
   204 	}
       
   205 	
       
   206 	/* For debugging purposes */
       
   207 	protected void printPkt() {
       
   208 		System.out.print("V:" + version + " P:" + padding + " EXT:" + extension);
       
   209 		System.out.println(" CC:" + getCsrcCount() + " M:"+ marker +" PT:" + payloadType + " SN: "+ seqNumber);
       
   210 		System.out.println("Timestamp:" + timeStamp + "(long output as int, may be 2s complement)");
       
   211 		System.out.println("SSRC:" + ssrc + "(long output as int, may be 2s complement)");
       
   212 		for(int i=0;i<getCsrcCount();i++) {
       
   213 			System.out.println("CSRC:" + csrcArray[i] + "(long output as int, may be 2s complement)");
       
   214 		}
       
   215 		//TODO Extension
       
   216 		System.out.println("Payload, first four bytes: " + payload[0] + " " + payload[1] + " " + payload[2] + " " + payload[3]);
       
   217 	}
       
   218 	/*********************************************************************************************************
       
   219 	 *                                                Setting stuff 
       
   220 	 *********************************************************************************************************/
       
   221 	protected void setMarked(boolean mark) {
       
   222 		rawPktCurrent = false;
       
   223 		if(mark) {
       
   224 			marker = 1;
       
   225 		} else {
       
   226 			marker = 0;
       
   227 		}
       
   228 	}
       
   229 	//public int setHeaderExtension() {
       
   230 	//TODO
       
   231 	//}	
       
   232 	protected int setPayloadType(int plType) {
       
   233 		int temp = (plType & 0x0000007F); // 7 bits, checks in RTPSession as well.
       
   234 		if(temp == plType) {
       
   235 			rawPktCurrent = false;
       
   236 			payloadType = temp;
       
   237 			return 0;
       
   238 		} else {
       
   239 			return -1;
       
   240 		}
       
   241 	}
       
   242 	
       
   243 	protected int setSeqNumber(int number) {
       
   244 		if(number <= 65536 && number >= 0) {
       
   245 			rawPktCurrent = false;
       
   246 			seqNumber = number;
       
   247 			return 0;
       
   248 		} else {
       
   249 			System.out.println("RtpPkt.setSeqNumber: invalid number");
       
   250 			return -1;
       
   251 		}
       
   252 	}
       
   253 	
       
   254 	protected int setTimeStamp(long time) {
       
   255 		rawPktCurrent = false;
       
   256 		timeStamp = time;
       
   257 		return 0;	//Naive for now
       
   258 	}
       
   259 	
       
   260 	protected int setSsrc(long source) {
       
   261 		rawPktCurrent = false;
       
   262 		ssrc = source;
       
   263 		return 0;	//Naive for now
       
   264 	}
       
   265 	
       
   266 	protected int setCsrcs(long[] contributors) {
       
   267 		if(contributors.length <= 16) {
       
   268 			csrcArray = contributors;
       
   269 			return 0;
       
   270 		} else {
       
   271 			System.out.println("RtpPkt.setCsrcs: Cannot have more than 16 CSRCs");
       
   272 			return -1;
       
   273 		}
       
   274 	}
       
   275 	
       
   276 	protected int setPayload(byte[] data) {
       
   277 		// TODO Padding
       
   278 		if(data.length < (1500 - 12)) {
       
   279 			rawPktCurrent = false;
       
   280 			payload = data;
       
   281 			return 0;
       
   282 		} else {
       
   283 			System.out.println("RtpPkt.setPayload: Cannot carry more than 1480 bytes for now.");
       
   284 			return -1;
       
   285 		}
       
   286 	}
       
   287 	protected byte[] getPayload() {
       
   288 		return payload;
       
   289 	}
       
   290 
       
   291 	/*********************************************************************************************************
       
   292 	 *                                           Private functions 
       
   293 	 *********************************************************************************************************/
       
   294 	//Generate a bytebyffer representing the packet, store it.
       
   295 	private void writePkt() {
       
   296 		int bytes = getPayloadLength();
       
   297 		int headerLen = getHeaderLength();
       
   298 		int csrcLen = getCsrcCount();
       
   299 		rawPkt = new byte[headerLen + bytes];
       
   300 		
       
   301 		// The first line contains, version and various bits
       
   302 		writeFirstLine();
       
   303 		byte[] someBytes = StaticProcs.uIntLongToByteWord(timeStamp);
       
   304 		for(int i=0;i<4;i++) {
       
   305 			rawPkt[i + 4] = someBytes[i];
       
   306 		}
       
   307 		//System.out.println("writePkt timeStamp:" + rawPkt[7]);
       
   308 		
       
   309 		someBytes = StaticProcs.uIntLongToByteWord(ssrc);
       
   310 		System.arraycopy(someBytes, 0, rawPkt, 8, 4);
       
   311 		//System.out.println("writePkt ssrc:" + rawPkt[11]);
       
   312 		
       
   313 		for(int i=0; i<csrcLen ; i++) {
       
   314 			someBytes = StaticProcs.uIntLongToByteWord(csrcArray[i]);
       
   315 			System.arraycopy(someBytes, 0, rawPkt, 12 + 4*i, 4);
       
   316 		}
       
   317 		// TODO Extension
       
   318 
       
   319 		//Payload
       
   320 		System.arraycopy(payload, 0, rawPkt, headerLen, bytes);
       
   321 		rawPktCurrent = true;
       
   322 	}
       
   323 	//Writes the first 4 octets of the RTP packet
       
   324 	private void writeFirstLine() {
       
   325 		byte aByte = 0;
       
   326 		aByte |=(version << 6);
       
   327 		aByte |=(padding << 5);
       
   328 		aByte |=(extension << 4);
       
   329 		aByte |=(getCsrcCount());
       
   330 		rawPkt[0] = aByte;
       
   331 		aByte = 0;
       
   332 		aByte |=(marker << 7);
       
   333 		aByte |= payloadType;
       
   334 		rawPkt[1] = aByte;
       
   335 		byte[] someBytes = StaticProcs.uIntIntToByteWord(seqNumber);
       
   336 		rawPkt[2] = someBytes[0];
       
   337 		rawPkt[3] = someBytes[1];
       
   338 	}
       
   339 	//Picks apart the first 4 octets of an RTP packet
       
   340 	private void sliceFirstLine() {
       
   341 		version = ((rawPkt[0] & 0xC0) >>> 6);
       
   342 		padding = ((rawPkt[0] & 0x20) >>> 5);
       
   343 		extension = ((rawPkt[0] & 0x10) >>> 4);
       
   344 		csrcArray = new long[(rawPkt[0] & 0x0F)];
       
   345 		marker = ((rawPkt[1] & 0x80) >> 7);
       
   346 		payloadType = (rawPkt[1] & 0x7F);
       
   347 		seqNumber = StaticProcs.bytesToUIntInt(rawPkt, 2);
       
   348 	}
       
   349 	//Takes the 4 octets representing the timestamp
       
   350 	private void sliceTimeStamp() {
       
   351 		timeStamp = StaticProcs.bytesToUIntLong(rawPkt, 4);
       
   352 	}
       
   353 	//Takes the 4 octets representing the SSRC
       
   354 	private void sliceSSRC() {
       
   355 		ssrc = StaticProcs.bytesToUIntLong(rawPkt,8);
       
   356 	}
       
   357 	//Check the length of the csrcArray (set during sliceFirstLine) 
       
   358 	private void  sliceCSRCs() {
       
   359 		for(int i=0; i< csrcArray.length; i++) {
       
   360 			ssrc = StaticProcs.bytesToUIntLong(rawPkt, i*4 + 12);
       
   361 		}
       
   362 	}
       
   363 	//Extensions //TODO
       
   364 	private void slicePayload(int bytes) {
       
   365 		payload = new byte[bytes];
       
   366 		int headerLen = getHeaderLength();
       
   367 		
       
   368 		System.arraycopy(rawPkt, headerLen, payload, 0, bytes);
       
   369 	}
       
   370 }