diff -r 537ddd8aa407 -r 2036ebfaccda src/jlibrtp/CompRtcpPkt.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/jlibrtp/CompRtcpPkt.java Fri Nov 20 19:29:42 2009 +0100 @@ -0,0 +1,268 @@ +/** + * Java RTP Library (jlibrtp) + * Copyright (C) 2006 Arne Kepp + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ +package jlibrtp; + +import java.net.InetSocketAddress; +import java.util.LinkedList; +import java.util.ListIterator; + +/** + * Compound RTCP packet class. + * + * It basically holds a list of packets. This list can either be constructed by + * providing a byte[] of a compound packet, or by adding individual packets. + * + * Upon encode(), the packet will call encode on all the added packets. + * + * problem == 0 indicates the parsing succeeded. + * + * + * @author Arne Kepp + */ + +public class CompRtcpPkt { + /** Problem indicator, negative values denote packet type that cause problem */ + protected int problem = 0; + /** + * Stores the different subclasses of RtcpPkt that make up the compound + * packet + */ + protected LinkedList rtcpPkts = new LinkedList(); + + /** + * Instantiates an empty Compound RTCP packet to which you can add RTCP + * packets + */ + protected CompRtcpPkt() { + // Will have to add packets directly to rtcpPkts. + if (RTPSession.rtpDebugLevel > 7) { + System.out.println("<-> CompRtcpPkt()"); + } + } + + /** + * Add a RTCP packet to the compound packet. Pakcets are added in order, so + * you have to ensure that a Sender Report or Receiver Report is added + * first. + * + * @param aPkt + * the packet to be added + */ + protected void addPacket(RtcpPkt aPkt) { + if (RTPSession.rtpDebugLevel > 11) { + System.out.println(" <-> CompRtcpPkt.addPacket( " + + aPkt.getClass() + " )"); + } + + if (aPkt.problem == 0) { + rtcpPkts.add(aPkt); + } else { + this.problem = aPkt.problem; + } + } + + /** + * Picks a received Compound RTCP packet apart. + * + * Only SDES packets are processed directly, other packets are parsed and + * put into aComptRtcpPkt.rtcpPkts, but not + * + * Check the aComptRtcpPkt.problem , if the value is non-zero the packets + * should probably be discarded. + * + * @param rawPkt + * the byte array received from the socket + * @param packetSize + * the actual number of used bytes + * @param adr + * the socket address from which the packet was received + * @param rtpSession + * the RTPSession with the participant database + */ + + protected void init(byte[] rawPkt, int packetSize, InetSocketAddress adr, + RTPSession rtpSession) { + if (RTPSession.rtcpDebugLevel > 7) { + System.out.println("-> CompRtcpPkt(" + rawPkt.getClass() + + ", size " + packetSize + ", from " + adr.toString() + + ", " + rtpSession.getClass() + ")"); + } + // System.out.println("rawPkt.length:" + rawPkt.length + " packetSize:" + // + packetSize); + + // Chop it up + int start = 0; + + while (start < packetSize && problem == 0) { + int length = (StaticProcs.bytesToUIntInt(rawPkt, start + 2)) + 1; + + if (length * 4 + start > rawPkt.length) { + System.out.println("!!!! CompRtcpPkt.(rawPkt,..,..) length (" + + (length * 4 + start) + + ") exceeds size of raw packet (" + rawPkt.length + + ") !"); + this.problem = -3; + } + + int pktType = (int) rawPkt[start + 1]; + + if (pktType < 0) { + pktType += 256; + } + + if (start == 0) { + // Compound packets need to start with SR or RR + if (pktType != 200 && pktType != 201) { + if (RTPSession.rtcpDebugLevel > 3) { + System.out + .println("!!!! CompRtcpPkt(rawPkt...) packet did not start with SR or RR"); + } + this.problem = -1; + } + + // Padding bit should be zero for the first packet + if (((rawPkt[start] & 0x20) >>> 5) == 1) { + if (RTPSession.rtcpDebugLevel > 3) { + System.out + .println("!!!! CompRtcpPkt(rawPkt...) first packet was padded"); + } + this.problem = -2; + } + } + + // System.out.println("start: " + start + " pktType: " + pktType + + // " length:" + length ); + if (pktType == 200) { + addPacket(new RtcpPktSR(rawPkt, start, length * 4)); + } else if (pktType == 201) { + addPacket(new RtcpPktRR(rawPkt, start, -1)); + } else if (pktType == 202) { + addPacket(new RtcpPktSDES(rawPkt, start, adr, rtpSession.partDb)); + } else if (pktType == 203) { + addPacket(new RtcpPktBYE(rawPkt, start)); + } else if (pktType == 204) { + addPacket(new RtcpPktAPP(rawPkt, start)); + } else if (pktType == 205) { + addPacket(new RtcpPktRTPFB(rawPkt, start, rtpSession)); + } else if (pktType == 206) { + addPacket(new RtcpPktPSFB(rawPkt, start, rtpSession)); + } else { + System.out + .println("!!!! CompRtcpPkt(byte[] rawPkt, int packetSize...) " + + "UNKNOWN RTCP PACKET TYPE:" + pktType); + } + + // System.out.println(" start:" + start + " pktType:" + pktType + + // " length:" + length); + + start += length * 4; + + if (RTPSession.rtcpDebugLevel > 12) { + System.out.println(" start:" + start + " parsing pktType " + + pktType + " length: " + length); + } + } + if (RTPSession.rtcpDebugLevel > 7) { + System.out.println("<- CompRtcpPkt(rawPkt....)"); + } + } + + /** + * Encode combines the RTCP packets in this.rtcpPkts into a byte[] by + * calling the encode() function on each of them individually. + * + * The order of rtcpPkts is preserved, so a RR or SR packet must be first. + * + * @return the trimmed byte[] representation of the packet, ready to go into + * a UDP packet. + */ + protected byte[] encode() { + if (RTPSession.rtpDebugLevel > 9) { + System.out.println(" <- CompRtcpPkt.encode()"); + } + + ListIterator iter = rtcpPkts.listIterator(); + + byte[] rawPkt = new byte[1500]; + int index = 0; + + while (iter.hasNext()) { + RtcpPkt aPkt = (RtcpPkt) iter.next(); + + if (aPkt.packetType == 200) { + RtcpPktSR pkt = (RtcpPktSR) aPkt; + pkt.encode(); + System.arraycopy(pkt.rawPkt, 0, rawPkt, index, + pkt.rawPkt.length); + index += pkt.rawPkt.length; + } else if (aPkt.packetType == 201) { + RtcpPktRR pkt = (RtcpPktRR) aPkt; + pkt.encode(); + System.arraycopy(pkt.rawPkt, 0, rawPkt, index, + pkt.rawPkt.length); + index += pkt.rawPkt.length; + } else if (aPkt.packetType == 202) { + RtcpPktSDES pkt = (RtcpPktSDES) aPkt; + pkt.encode(); + // System.out.println(" ENCODE SIZE: " + pkt.rawPkt.length); + System.arraycopy(pkt.rawPkt, 0, rawPkt, index, + pkt.rawPkt.length); + index += pkt.rawPkt.length; + } else if (aPkt.packetType == 203) { + RtcpPktBYE pkt = (RtcpPktBYE) aPkt; + pkt.encode(); + System.arraycopy(pkt.rawPkt, 0, rawPkt, index, + pkt.rawPkt.length); + index += pkt.rawPkt.length; + } else if (aPkt.packetType == 204) { + RtcpPktAPP pkt = (RtcpPktAPP) aPkt; + pkt.encode(); + System.arraycopy(pkt.rawPkt, 0, rawPkt, index, + pkt.rawPkt.length); + index += pkt.rawPkt.length; + } else if (aPkt.packetType == 205) { + RtcpPktRTPFB pkt = (RtcpPktRTPFB) aPkt; + pkt.encode(); + System.arraycopy(pkt.rawPkt, 0, rawPkt, index, + pkt.rawPkt.length); + index += pkt.rawPkt.length; + } else if (aPkt.packetType == 206) { + RtcpPktPSFB pkt = (RtcpPktPSFB) aPkt; + pkt.encode(); + System.arraycopy(pkt.rawPkt, 0, rawPkt, index, + pkt.rawPkt.length); + index += pkt.rawPkt.length; + } else { + System.out.println("CompRtcpPkt aPkt.packetType:" + + aPkt.packetType); + } + // System.out.println(" packetType:" + aPkt.packetType + " length:" + // + aPkt.rawPkt.length + " index:" + index); + } + + byte[] output = new byte[index]; + + System.arraycopy(rawPkt, 0, output, 0, index); + + if (RTPSession.rtpDebugLevel > 9) { + System.out.println(" -> CompRtcpPkt.encode()"); + } + return output; + } +} \ No newline at end of file