src/jlibrtp/CompRtcpPkt.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.InetSocketAddress;
       
    22 import java.util.LinkedList;
       
    23 import java.util.ListIterator;
       
    24 
       
    25 /**
       
    26  * Compound RTCP packet class.
       
    27  * 
       
    28  * It basically holds a list of packets. This list can either be constructed by
       
    29  * providing a byte[] of a compound packet, or by adding individual packets.
       
    30  * 
       
    31  * Upon encode(), the packet will call encode on all the added packets.
       
    32  * 
       
    33  * problem == 0 indicates the parsing succeeded.
       
    34  * 
       
    35  * 
       
    36  * @author Arne Kepp
       
    37  */
       
    38 
       
    39 public class CompRtcpPkt {
       
    40 	/** Problem indicator, negative values denote packet type that cause problem */
       
    41 	protected int problem = 0;
       
    42 	/**
       
    43 	 * Stores the different subclasses of RtcpPkt that make up the compound
       
    44 	 * packet
       
    45 	 */
       
    46 	protected LinkedList<RtcpPkt> rtcpPkts = new LinkedList<RtcpPkt>();
       
    47 
       
    48 	/**
       
    49 	 * Instantiates an empty Compound RTCP packet to which you can add RTCP
       
    50 	 * packets
       
    51 	 */
       
    52 	protected CompRtcpPkt() {
       
    53 		// Will have to add packets directly to rtcpPkts.
       
    54 		if (RTPSession.rtpDebugLevel > 7) {
       
    55 			System.out.println("<-> CompRtcpPkt()");
       
    56 		}
       
    57 	}
       
    58 
       
    59 	/**
       
    60 	 * Add a RTCP packet to the compound packet. Pakcets are added in order, so
       
    61 	 * you have to ensure that a Sender Report or Receiver Report is added
       
    62 	 * first.
       
    63 	 * 
       
    64 	 * @param aPkt
       
    65 	 *            the packet to be added
       
    66 	 */
       
    67 	protected void addPacket(RtcpPkt aPkt) {
       
    68 		if (RTPSession.rtpDebugLevel > 11) {
       
    69 			System.out.println("  <-> CompRtcpPkt.addPacket( "
       
    70 					+ aPkt.getClass() + " )");
       
    71 		}
       
    72 
       
    73 		if (aPkt.problem == 0) {
       
    74 			rtcpPkts.add(aPkt);
       
    75 		} else {
       
    76 			this.problem = aPkt.problem;
       
    77 		}
       
    78 	}
       
    79 	
       
    80 	/**
       
    81 	 * Picks a received Compound RTCP packet apart.
       
    82 	 * 
       
    83 	 * Only SDES packets are processed directly, other packets are parsed and
       
    84 	 * put into aComptRtcpPkt.rtcpPkts, but not
       
    85 	 * 
       
    86 	 * Check the aComptRtcpPkt.problem , if the value is non-zero the packets
       
    87 	 * should probably be discarded.
       
    88 	 * 
       
    89 	 * @param rawPkt
       
    90 	 *            the byte array received from the socket
       
    91 	 * @param packetSize
       
    92 	 *            the actual number of used bytes
       
    93 	 * @param adr
       
    94 	 *            the socket address from which the packet was received
       
    95 	 * @param rtpSession
       
    96 	 *            the RTPSession with the participant database
       
    97 	 */
       
    98 	
       
    99 	protected void init(byte[] rawPkt, int packetSize, InetSocketAddress adr,
       
   100 			RTPSession rtpSession) {
       
   101 		if (RTPSession.rtcpDebugLevel > 7) {
       
   102 			System.out.println("-> CompRtcpPkt(" + rawPkt.getClass()
       
   103 					+ ", size " + packetSize + ", from " + adr.toString()
       
   104 					+ ", " + rtpSession.getClass() + ")");
       
   105 		}
       
   106 		// System.out.println("rawPkt.length:" + rawPkt.length + " packetSize:"
       
   107 		// + packetSize);
       
   108 
       
   109 		// Chop it up
       
   110 		int start = 0;
       
   111 
       
   112 		while (start < packetSize && problem == 0) {
       
   113 			int length = (StaticProcs.bytesToUIntInt(rawPkt, start + 2)) + 1;
       
   114 
       
   115 			if (length * 4 + start > rawPkt.length) {
       
   116 				System.out.println("!!!! CompRtcpPkt.(rawPkt,..,..) length ("
       
   117 						+ (length * 4 + start)
       
   118 						+ ") exceeds size of raw packet (" + rawPkt.length
       
   119 						+ ") !");
       
   120 				this.problem = -3;
       
   121 			}
       
   122 
       
   123 			int pktType = (int) rawPkt[start + 1];
       
   124 
       
   125 			if (pktType < 0) {
       
   126 				pktType += 256;
       
   127 			}
       
   128 
       
   129 			if (start == 0) {
       
   130 				// Compound packets need to start with SR or RR
       
   131 				if (pktType != 200 && pktType != 201) {
       
   132 					if (RTPSession.rtcpDebugLevel > 3) {
       
   133 						System.out
       
   134 								.println("!!!! CompRtcpPkt(rawPkt...) packet did not start with SR or RR");
       
   135 					}
       
   136 					this.problem = -1;
       
   137 				}
       
   138 
       
   139 				// Padding bit should be zero for the first packet
       
   140 				if (((rawPkt[start] & 0x20) >>> 5) == 1) {
       
   141 					if (RTPSession.rtcpDebugLevel > 3) {
       
   142 						System.out
       
   143 								.println("!!!! CompRtcpPkt(rawPkt...) first packet was padded");
       
   144 					}
       
   145 					this.problem = -2;
       
   146 				}
       
   147 			}
       
   148 
       
   149 			// System.out.println("start: " + start + "   pktType: " + pktType +
       
   150 			// "  length:" + length );
       
   151 			if (pktType == 200) {
       
   152 				addPacket(new RtcpPktSR(rawPkt, start, length * 4));
       
   153 			} else if (pktType == 201) {
       
   154 				addPacket(new RtcpPktRR(rawPkt, start, -1));
       
   155 			} else if (pktType == 202) {
       
   156 				addPacket(new RtcpPktSDES(rawPkt, start, adr, rtpSession.partDb));
       
   157 			} else if (pktType == 203) {
       
   158 				addPacket(new RtcpPktBYE(rawPkt, start));
       
   159 			} else if (pktType == 204) {
       
   160 				addPacket(new RtcpPktAPP(rawPkt, start));
       
   161 			} else if (pktType == 205) {
       
   162 				addPacket(new RtcpPktRTPFB(rawPkt, start, rtpSession));
       
   163 			} else if (pktType == 206) {
       
   164 				addPacket(new RtcpPktPSFB(rawPkt, start, rtpSession));
       
   165 			} else {
       
   166 				System.out
       
   167 						.println("!!!! CompRtcpPkt(byte[] rawPkt, int packetSize...) "
       
   168 								+ "UNKNOWN RTCP PACKET TYPE:" + pktType);
       
   169 			}
       
   170 
       
   171 			// System.out.println(" start:" + start + "  pktType:" + pktType +
       
   172 			// " length:" + length);
       
   173 
       
   174 			start += length * 4;
       
   175 
       
   176 			if (RTPSession.rtcpDebugLevel > 12) {
       
   177 				System.out.println(" start:" + start + "  parsing pktType "
       
   178 						+ pktType + " length: " + length);
       
   179 			}
       
   180 		}
       
   181 		if (RTPSession.rtcpDebugLevel > 7) {
       
   182 			System.out.println("<- CompRtcpPkt(rawPkt....)");
       
   183 		}
       
   184 	}
       
   185 
       
   186 	/**
       
   187 	 * Encode combines the RTCP packets in this.rtcpPkts into a byte[] by
       
   188 	 * calling the encode() function on each of them individually.
       
   189 	 * 
       
   190 	 * The order of rtcpPkts is preserved, so a RR or SR packet must be first.
       
   191 	 * 
       
   192 	 * @return the trimmed byte[] representation of the packet, ready to go into
       
   193 	 *         a UDP packet.
       
   194 	 */
       
   195 	protected byte[] encode() {
       
   196 		if (RTPSession.rtpDebugLevel > 9) {
       
   197 			System.out.println(" <- CompRtcpPkt.encode()");
       
   198 		}
       
   199 
       
   200 		ListIterator<RtcpPkt> iter = rtcpPkts.listIterator();
       
   201 
       
   202 		byte[] rawPkt = new byte[1500];
       
   203 		int index = 0;
       
   204 
       
   205 		while (iter.hasNext()) {
       
   206 			RtcpPkt aPkt = (RtcpPkt) iter.next();
       
   207 
       
   208 			if (aPkt.packetType == 200) {
       
   209 				RtcpPktSR pkt = (RtcpPktSR) aPkt;
       
   210 				pkt.encode();
       
   211 				System.arraycopy(pkt.rawPkt, 0, rawPkt, index,
       
   212 						pkt.rawPkt.length);
       
   213 				index += pkt.rawPkt.length;
       
   214 			} else if (aPkt.packetType == 201) {
       
   215 				RtcpPktRR pkt = (RtcpPktRR) aPkt;
       
   216 				pkt.encode();
       
   217 				System.arraycopy(pkt.rawPkt, 0, rawPkt, index,
       
   218 						pkt.rawPkt.length);
       
   219 				index += pkt.rawPkt.length;
       
   220 			} else if (aPkt.packetType == 202) {
       
   221 				RtcpPktSDES pkt = (RtcpPktSDES) aPkt;
       
   222 				pkt.encode();
       
   223 				// System.out.println(" ENCODE SIZE: " + pkt.rawPkt.length);
       
   224 				System.arraycopy(pkt.rawPkt, 0, rawPkt, index,
       
   225 						pkt.rawPkt.length);
       
   226 				index += pkt.rawPkt.length;
       
   227 			} else if (aPkt.packetType == 203) {
       
   228 				RtcpPktBYE pkt = (RtcpPktBYE) aPkt;
       
   229 				pkt.encode();
       
   230 				System.arraycopy(pkt.rawPkt, 0, rawPkt, index,
       
   231 						pkt.rawPkt.length);
       
   232 				index += pkt.rawPkt.length;
       
   233 			} else if (aPkt.packetType == 204) {
       
   234 				RtcpPktAPP pkt = (RtcpPktAPP) aPkt;
       
   235 				pkt.encode();
       
   236 				System.arraycopy(pkt.rawPkt, 0, rawPkt, index,
       
   237 						pkt.rawPkt.length);
       
   238 				index += pkt.rawPkt.length;
       
   239 			} else if (aPkt.packetType == 205) {
       
   240 				RtcpPktRTPFB pkt = (RtcpPktRTPFB) aPkt;
       
   241 				pkt.encode();
       
   242 				System.arraycopy(pkt.rawPkt, 0, rawPkt, index,
       
   243 						pkt.rawPkt.length);
       
   244 				index += pkt.rawPkt.length;
       
   245 			} else if (aPkt.packetType == 206) {
       
   246 				RtcpPktPSFB pkt = (RtcpPktPSFB) aPkt;
       
   247 				pkt.encode();
       
   248 				System.arraycopy(pkt.rawPkt, 0, rawPkt, index,
       
   249 						pkt.rawPkt.length);
       
   250 				index += pkt.rawPkt.length;
       
   251 			} else {
       
   252 				System.out.println("CompRtcpPkt aPkt.packetType:"
       
   253 						+ aPkt.packetType);
       
   254 			}
       
   255 			// System.out.println(" packetType:" + aPkt.packetType + " length:"
       
   256 			// + aPkt.rawPkt.length + " index:" + index);
       
   257 		}
       
   258 
       
   259 		byte[] output = new byte[index];
       
   260 
       
   261 		System.arraycopy(rawPkt, 0, output, 0, index);
       
   262 
       
   263 		if (RTPSession.rtpDebugLevel > 9) {
       
   264 			System.out.println(" -> CompRtcpPkt.encode()");
       
   265 		}
       
   266 		return output;
       
   267 	}
       
   268 }