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