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