public RtcpPacket parseRtcpPacket(Packet packet){
  RtcpCompoundPacket compoundPacket=new RtcpCompoundPacket(packet);
  Vector<RtcpPacket> subpackets=new Vector<RtcpPacket>();
  DataInputStream in=new DataInputStream(new ByteArrayInputStream(compoundPacket.data,compoundPacket.offset,compoundPacket.length));
  try {
    rtcpSession.updateavgrtcpsize(compoundPacket.length);
    int length=0;
    for (int offset=0; offset < compoundPacket.length; offset+=length) {
      int firstbyte=in.readUnsignedByte();
      if ((firstbyte & 0xc0) != 128) {
        return null;
      }
      int type=in.readUnsignedByte();
      length=in.readUnsignedShort();
      length=length + 1 << 2;
      int padlen=0;
      if (offset + length > compoundPacket.length) {
        return null;
      }
      if (offset + length == compoundPacket.length) {
        if ((firstbyte & 0x20) != 0) {
          padlen=compoundPacket.data[compoundPacket.offset + compoundPacket.length - 1] & 0xff;
          if (padlen == 0) {
            return null;
          }
        }
      }
 else       if ((firstbyte & 0x20) != 0) {
        return null;
      }
      int inlength=length - padlen;
      firstbyte&=0x1f;
      RtcpPacket subpacket;
switch (type) {
case RtcpPacket.RTCP_SR:
        stats.numSrPkts++;
      if (inlength != 28 + 24 * firstbyte) {
        stats.numMalformedRtcpPkts++;
        return null;
      }
    RtcpSenderReportPacket srp=new RtcpSenderReportPacket(compoundPacket);
  subpacket=srp;
srp.ssrc=in.readInt();
srp.ntptimestampmsw=(long)in.readInt() & 0xffffffffL;
srp.ntptimestamplsw=(long)in.readInt() & 0xffffffffL;
srp.rtptimestamp=(long)in.readInt() & 0xffffffffL;
srp.packetcount=(long)in.readInt() & 0xffffffffL;
srp.octetcount=(long)in.readInt() & 0xffffffffL;
srp.reports=new RtcpReport[firstbyte];
RtpSource sourceSR=rtcpSession.getMySource();
if (sourceSR != null) {
sourceSR.receivedSenderReport(srp);
}
for (int i=0; i < srp.reports.length; i++) {
RtcpReport report=new RtcpReport();
srp.reports[i]=report;
report.ssrc=in.readInt();
long val=in.readInt();
val&=0xffffffffL;
report.fractionlost=(int)(val >> 24);
report.packetslost=(int)(val & 0xffffffL);
report.lastseq=(long)in.readInt() & 0xffffffffL;
report.jitter=in.readInt();
report.lsr=(long)in.readInt() & 0xffffffffL;
report.dlsr=(long)in.readInt() & 0xffffffffL;
}
notifyRtcpListeners(new RtcpSenderReportEvent(srp));
break;
case RtcpPacket.RTCP_RR:
if (inlength != 8 + 24 * firstbyte) {
stats.numMalformedRtcpPkts++;
return null;
}
RtcpReceiverReportPacket rrp=new RtcpReceiverReportPacket(compoundPacket);
subpacket=rrp;
rrp.ssrc=in.readInt();
rrp.reports=new RtcpReport[firstbyte];
for (int i=0; i < rrp.reports.length; i++) {
RtcpReport report=new RtcpReport();
rrp.reports[i]=report;
report.ssrc=in.readInt();
long val=in.readInt();
val&=0xffffffffL;
report.fractionlost=(int)(val >> 24);
report.packetslost=(int)(val & 0xffffffL);
report.lastseq=(long)in.readInt() & 0xffffffffL;
report.jitter=in.readInt();
report.lsr=(long)in.readInt() & 0xffffffffL;
report.dlsr=(long)in.readInt() & 0xffffffffL;
}
notifyRtcpListeners(new RtcpReceiverReportEvent(rrp));
break;
case RtcpPacket.RTCP_SDES:
RtcpSdesPacket sdesp=new RtcpSdesPacket(compoundPacket);
subpacket=sdesp;
sdesp.sdes=new RtcpSdesBlock[firstbyte];
int sdesoff=4;
for (int i=0; i < sdesp.sdes.length; i++) {
RtcpSdesBlock chunk=new RtcpSdesBlock();
sdesp.sdes[i]=chunk;
chunk.ssrc=in.readInt();
sdesoff+=5;
Vector<RtcpSdesItem> items=new Vector<RtcpSdesItem>();
boolean gotcname=false;
int j;
while ((j=in.readUnsignedByte()) != 0) {
if (j < 1 || j > 8) {
stats.numMalformedRtcpPkts++;
return null;
}
if (j == 1) {
gotcname=true;
}
RtcpSdesItem item=new RtcpSdesItem();
items.addElement(item);
item.type=j;
int sdeslen=in.readUnsignedByte();
item.data=new byte[sdeslen];
in.readFully(item.data);
sdesoff+=2 + sdeslen;
}
if (!gotcname) {
stats.numMalformedRtcpPkts++;
return null;
}
chunk.items=new RtcpSdesItem[items.size()];
items.copyInto(chunk.items);
if ((sdesoff & 3) != 0) {
if (in.skip(4 - (sdesoff & 3)) != 4 - (sdesoff & 3)) {
return null;
}
sdesoff=sdesoff + 3 & -4;
}
}
if (inlength != sdesoff) {
stats.numMalformedRtcpPkts++;
return null;
}
notifyRtcpListeners(new RtcpSdesEvent(sdesp));
break;
case RtcpPacket.RTCP_BYE:
RtcpByePacket byep=new RtcpByePacket(compoundPacket);
subpacket=byep;
byep.ssrc=new int[firstbyte];
for (int i=0; i < byep.ssrc.length; i++) {
byep.ssrc[i]=in.readInt();
}
int reasonlen;
if (inlength > 4 + 4 * firstbyte) {
reasonlen=in.readUnsignedByte();
byep.reason=new byte[reasonlen];
reasonlen++;
}
 else {
reasonlen=0;
byep.reason=new byte[0];
}
reasonlen=reasonlen + 3 & -4;
if (inlength != 4 + 4 * firstbyte + reasonlen) {
stats.numMalformedRtcpPkts++;
return null;
}
in.readFully(byep.reason);
int skipBye=reasonlen - byep.reason.length;
if (in.skip(skipBye) != skipBye) {
return null;
}
notifyRtcpListeners(new RtcpByeEvent(byep));
break;
case RtcpPacket.RTCP_APP:
if (inlength < 12) {
return null;
}
RtcpAppPacket appp=new RtcpAppPacket(compoundPacket);
subpacket=appp;
appp.ssrc=in.readInt();
appp.name=in.readInt();
appp.subtype=firstbyte;
appp.data=new byte[inlength - 12];
in.readFully(appp.data);
int skipApp=inlength - 12 - appp.data.length;
if (in.skip(skipApp) != skipApp) {
return null;
}
notifyRtcpListeners(new RtcpApplicationEvent(appp));
break;
default :
stats.numUnknownTypes++;
return null;
}
subpacket.offset=offset;
subpacket.length=length;
subpackets.addElement(subpacket);
if (in.skipBytes(padlen) != padlen) {
return null;
}
}
}
 catch (Exception e) {
return null;
}
compoundPacket.packets=new RtcpPacket[subpackets.size()];
subpackets.copyInto(compoundPacket.packets);
return compoundPacket;
}

public RtcpPacket parseRtcpPacket ( Packet packet ) { RtcpCompoundPacket compoundPacket = new RtcpCompoundPacket ( packet ) ; Vector < RtcpPacket > subpackets = new Vector < RtcpPacket > ( ) ; DataInputStream in = new DataInputStream ( new ByteArrayInputStream ( compoundPacket . data , compoundPacket . offset , compoundPacket . length ) ) ; try { rtcpSession . updateavgrtcpsize ( compoundPacket . length ) ; int length = 0 ; for ( int offset = 0 ; offset < compoundPacket . length ; offset += length ) { int firstbyte = in . readUnsignedByte ( ) ; if ( ( firstbyte & 0xc0 ) != 128 ) { return null ; } int type = in . readUnsignedByte ( ) ; length = in . readUnsignedShort ( ) ; length = length + 1 << 2 ; int padlen = 0 ; if ( offset + length > compoundPacket . length ) { return null ; } if ( offset + length == compoundPacket . length ) { if ( ( firstbyte & 0x20 ) != 0 ) { padlen = compoundPacket . data [ compoundPacket . offset + compoundPacket . length - 1 ] & 0xff ; if ( padlen == 0 ) { return null ; } } } else if ( ( firstbyte & 0x20 ) != 0 ) { return null ; } int inlength = length - padlen ; firstbyte &= 0x1f ; RtcpPacket subpacket ; switch ( type ) { case RtcpPacket . RTCP_SR : stats . numSrPkts ++ ; if ( inlength != 28 + 24 * firstbyte ) { stats . numMalformedRtcpPkts ++ ; return null ; } RtcpSenderReportPacket srp = new RtcpSenderReportPacket ( compoundPacket ) ; subpacket = srp ; srp . ssrc = in . readInt ( ) ; srp . ntptimestampmsw = ( long ) in . readInt ( ) & 0xffffffffL ; srp . ntptimestamplsw = ( long ) in . readInt ( ) & 0xffffffffL ; srp . rtptimestamp = ( long ) in . readInt ( ) & 0xffffffffL ; srp . packetcount = ( long ) in . readInt ( ) & 0xffffffffL ; srp . octetcount = ( long ) in . readInt ( ) & 0xffffffffL ; srp . reports = new RtcpReport [ firstbyte ] ; RtpSource sourceSR = rtcpSession . getMySource ( ) ; if ( sourceSR != null ) { sourceSR . receivedSenderReport ( srp ) ; } for ( int i = 0 ; i < srp . reports . length ; i ++ ) { RtcpReport report = new RtcpReport ( ) ; srp . reports [ i ] = report ; report . ssrc = in . readInt ( ) ; long val = in . readInt ( ) ; val &= 0xffffffffL ; report . fractionlost = ( int ) ( val > > 24 ) ; report . packetslost = ( int ) ( val & 0xffffffL ) ; report . lastseq = ( long ) in . readInt ( ) & 0xffffffffL ; report . jitter = in . readInt ( ) ; report . lsr = ( long ) in . readInt ( ) & 0xffffffffL ; report . dlsr = ( long ) in . readInt ( ) & 0xffffffffL ; } notifyRtcpListeners ( new RtcpSenderReportEvent ( srp ) ) ; break ; case RtcpPacket . RTCP_RR : if ( inlength != 8 + 24 * firstbyte ) { stats . numMalformedRtcpPkts ++ ; return null ; } RtcpReceiverReportPacket rrp = new RtcpReceiverReportPacket ( compoundPacket ) ; subpacket = rrp ; rrp . ssrc = in . readInt ( ) ; rrp . reports = new RtcpReport [ firstbyte ] ; for ( int i = 0 ; i < rrp . reports . length ; i ++ ) { RtcpReport report = new RtcpReport ( ) ; rrp . reports [ i ] = report ; report . ssrc = in . readInt ( ) ; long val = in . readInt ( ) ; val &= 0xffffffffL ; report . fractionlost = ( int ) ( val > > 24 ) ; report . packetslost = ( int ) ( val & 0xffffffL ) ; report . lastseq = ( long ) in . readInt ( ) & 0xffffffffL ; report . jitter = in . readInt ( ) ; report . lsr = ( long ) in . readInt ( ) & 0xffffffffL ; report . dlsr = ( long ) in . readInt ( ) & 0xffffffffL ; } notifyRtcpListeners ( new RtcpReceiverReportEvent ( rrp ) ) ; break ; case RtcpPacket . RTCP_SDES : RtcpSdesPacket sdesp = new RtcpSdesPacket ( compoundPacket ) ; subpacket = sdesp ; sdesp . sdes = new RtcpSdesBlock [ firstbyte ] ; int sdesoff = 4 ; for ( int i = 0 ; i < sdesp . sdes . length ; i ++ ) { RtcpSdesBlock chunk = new RtcpSdesBlock ( ) ; sdesp . sdes [ i ] = chunk ; chunk . ssrc = in . readInt ( ) ; sdesoff += 5 ; Vector < RtcpSdesItem > items = new Vector < RtcpSdesItem > ( ) ; boolean gotcname = false ; int j ; while ( ( j = in . readUnsignedByte ( ) ) != 0 ) { if ( j < 1 || j > 8 ) { stats . numMalformedRtcpPkts ++ ; return null ; } if ( j == 1 ) { gotcname = true ; } RtcpSdesItem item = new RtcpSdesItem ( ) ; items . addElement ( item ) ; item . type = j ; int sdeslen = in . readUnsignedByte ( ) ; item . data = new byte [ sdeslen ] ; in . readFully ( item . data ) ; sdesoff += 2 + sdeslen ; } if ( ! gotcname ) { stats . numMalformedRtcpPkts ++ ; return null ; } chunk . items = new RtcpSdesItem [ items . size ( ) ] ; items . copyInto ( chunk . items ) ; if ( ( sdesoff & 3 ) != 0 ) { if ( in . skip ( 4 - ( sdesoff & 3 ) ) != 4 - ( sdesoff & 3 ) ) { return null ; } sdesoff = sdesoff + 3 & - 4 ; } } if ( inlength != sdesoff ) { stats . numMalformedRtcpPkts ++ ; return null ; } notifyRtcpListeners ( new RtcpSdesEvent ( sdesp ) ) ; break ; case RtcpPacket . RTCP_BYE : RtcpByePacket byep = new RtcpByePacket ( compoundPacket ) ; subpacket = byep ; byep . ssrc = new int [ firstbyte ] ; for ( int i = 0 ; i < byep . ssrc . length ; i ++ ) { byep . ssrc [ i ] = in . readInt ( ) ; } int reasonlen ; if ( inlength > 4 + 4 * firstbyte ) { reasonlen = in . readUnsignedByte ( ) ; byep . reason = new byte [ reasonlen ] ; reasonlen ++ ; } else { reasonlen = 0 ; byep . reason = new byte [ 0 ] ; } reasonlen = reasonlen + 3 & - 4 ; if ( inlength != 4 + 4 * firstbyte + reasonlen ) { stats . numMalformedRtcpPkts ++ ; return null ; } in . readFully ( byep . reason ) ; int skipBye = reasonlen - byep . reason . length ; if ( in . skip ( skipBye ) != skipBye ) { return null ; } notifyRtcpListeners ( new RtcpByeEvent ( byep ) ) ; break ; case RtcpPacket . RTCP_APP : if ( inlength < 12 ) { return null ; } RtcpAppPacket appp = new RtcpAppPacket ( compoundPacket ) ; subpacket = appp ; appp . ssrc = in . readInt ( ) ; appp . name = in . readInt ( ) ; appp . subtype = firstbyte ; appp . data = new byte [ inlength - 12 ] ; in . readFully ( appp . data ) ; int skipApp = inlength - 12 - appp . data . length ; if ( in . skip ( skipApp ) != skipApp ) { return null ; } notifyRtcpListeners ( new RtcpApplicationEvent ( appp ) ) ; break ; default : stats . numUnknownTypes ++ ; return null ; } subpacket . offset = offset ; subpacket . length = length ; subpackets . addElement ( subpacket ) ; if ( in . skipBytes ( padlen ) != padlen ) { return null ; } } } catch ( Exception e ) { return null ; } compoundPacket . packets = new RtcpPacket [ subpackets . size ( ) ] ; subpackets . copyInto ( compoundPacket . packets ) ; return compoundPacket ; }
parse the rtcp packet
