Add SDES, APP, IJ, SLI and PLI packet types to RTCP packet class.

BUG=2450
R=mflodman@webrtc.org, stefan@webrtc.org

Review URL: https://webrtc-codereview.appspot.com/19559004

git-svn-id: http://webrtc.googlecode.com/svn/trunk@6449 4adac7df-926f-26a2-2b94-8c16560cd09d
diff --git a/webrtc/modules/rtp_rtcp/source/rtcp_packet.cc b/webrtc/modules/rtp_rtcp/source/rtcp_packet.cc
index 51c86aa..a4cdfd9 100644
--- a/webrtc/modules/rtp_rtcp/source/rtcp_packet.cc
+++ b/webrtc/modules/rtp_rtcp/source/rtcp_packet.cc
@@ -13,21 +13,39 @@
 #include "webrtc/modules/rtp_rtcp/source/rtp_utility.h"
 #include "webrtc/system_wrappers/interface/logging.h"
 
+using webrtc::RTCPUtility::PT_APP;
 using webrtc::RTCPUtility::PT_BYE;
+using webrtc::RTCPUtility::PT_IJ;
 using webrtc::RTCPUtility::PT_PSFB;
 using webrtc::RTCPUtility::PT_RR;
 using webrtc::RTCPUtility::PT_RTPFB;
+using webrtc::RTCPUtility::PT_SDES;
 using webrtc::RTCPUtility::PT_SR;
+using webrtc::RTCPUtility::PT_XR;
 
+using webrtc::RTCPUtility::RTCPPacketAPP;
 using webrtc::RTCPUtility::RTCPPacketBYE;
+using webrtc::RTCPUtility::RTCPPacketPSFBAPP;
 using webrtc::RTCPUtility::RTCPPacketPSFBFIR;
 using webrtc::RTCPUtility::RTCPPacketPSFBFIRItem;
+using webrtc::RTCPUtility::RTCPPacketPSFBPLI;
+using webrtc::RTCPUtility::RTCPPacketPSFBREMBItem;
 using webrtc::RTCPUtility::RTCPPacketPSFBRPSI;
+using webrtc::RTCPUtility::RTCPPacketPSFBSLI;
+using webrtc::RTCPUtility::RTCPPacketPSFBSLIItem;
 using webrtc::RTCPUtility::RTCPPacketReportBlockItem;
 using webrtc::RTCPUtility::RTCPPacketRR;
 using webrtc::RTCPUtility::RTCPPacketRTPFBNACK;
 using webrtc::RTCPUtility::RTCPPacketRTPFBNACKItem;
+using webrtc::RTCPUtility::RTCPPacketRTPFBTMMBN;
+using webrtc::RTCPUtility::RTCPPacketRTPFBTMMBNItem;
+using webrtc::RTCPUtility::RTCPPacketRTPFBTMMBR;
+using webrtc::RTCPUtility::RTCPPacketRTPFBTMMBRItem;
 using webrtc::RTCPUtility::RTCPPacketSR;
+using webrtc::RTCPUtility::RTCPPacketXRDLRRReportBlockItem;
+using webrtc::RTCPUtility::RTCPPacketXRReceiverReferenceTimeItem;
+using webrtc::RTCPUtility::RTCPPacketXR;
+using webrtc::RTCPUtility::RTCPPacketXRVOIPMetricItem;
 
 namespace webrtc {
 namespace rtcp {
@@ -35,23 +53,23 @@
 // Unused SSRC of media source, set to 0.
 const uint32_t kUnusedMediaSourceSsrc0 = 0;
 
-void AssignUWord8(uint8_t* buffer, uint16_t* offset, uint8_t value) {
+void AssignUWord8(uint8_t* buffer, size_t* offset, uint8_t value) {
   buffer[(*offset)++] = value;
 }
-void AssignUWord16(uint8_t* buffer, uint16_t* offset, uint16_t value) {
+void AssignUWord16(uint8_t* buffer, size_t* offset, uint16_t value) {
   ModuleRTPUtility::AssignUWord16ToBuffer(buffer + *offset, value);
   *offset += 2;
 }
-void AssignUWord24(uint8_t* buffer, uint16_t* offset, uint32_t value) {
+void AssignUWord24(uint8_t* buffer, size_t* offset, uint32_t value) {
   ModuleRTPUtility::AssignUWord24ToBuffer(buffer + *offset, value);
   *offset += 3;
 }
-void AssignUWord32(uint8_t* buffer, uint16_t* offset, uint32_t value) {
+void AssignUWord32(uint8_t* buffer, size_t* offset, uint32_t value) {
   ModuleRTPUtility::AssignUWord32ToBuffer(buffer + *offset, value);
   *offset += 4;
 }
 
-uint16_t BlockToHeaderLength(uint16_t length_in_bytes) {
+size_t BlockToHeaderLength(size_t length_in_bytes) {
   // Length in 32-bit words minus 1.
   assert(length_in_bytes > 0);
   assert(length_in_bytes % 4 == 0);
@@ -69,9 +87,10 @@
 
 void CreateHeader(uint8_t count_or_format,  // Depends on packet type.
                   uint8_t packet_type,
-                  uint16_t length,
+                  size_t length,
                   uint8_t* buffer,
-                  uint16_t* pos) {
+                  size_t* pos) {
+  assert(length <= 0xffff);
   const uint8_t kVersion = 2;
   AssignUWord8(buffer, pos, (kVersion << 6) + count_or_format);
   AssignUWord8(buffer, pos, packet_type);
@@ -98,9 +117,9 @@
 //  +=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+
 
 void CreateSenderReport(const RTCPPacketSR& sr,
-                        uint16_t length,
+                        size_t length,
                         uint8_t* buffer,
-                        uint16_t* pos) {
+                        size_t* pos) {
   CreateHeader(sr.NumberOfReportBlocks, PT_SR, length, buffer, pos);
   AssignUWord32(buffer, pos, sr.SenderSSRC);
   AssignUWord32(buffer, pos, sr.NTPMostSignificant);
@@ -120,9 +139,9 @@
 //  +=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+
 
 void CreateReceiverReport(const RTCPPacketRR& rr,
-                          uint16_t length,
+                          size_t length,
                           uint8_t* buffer,
-                          uint16_t* pos) {
+                          size_t* pos) {
   CreateHeader(rr.NumberOfReportBlocks, PT_RR, length, buffer, pos);
   AssignUWord32(buffer, pos, rr.SenderSSRC);
 }
@@ -144,16 +163,89 @@
 //  |                   delay since last SR (DLSR)                  |
 //  +=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+
 
-void CreateReportBlock(const RTCPPacketReportBlockItem& report_block,
-                       uint8_t* buffer,
-                       uint16_t* pos) {
-  AssignUWord32(buffer, pos, report_block.SSRC);
-  AssignUWord8(buffer, pos, report_block.FractionLost);
-  AssignUWord24(buffer, pos, report_block.CumulativeNumOfPacketsLost);
-  AssignUWord32(buffer, pos, report_block.ExtendedHighestSequenceNumber);
-  AssignUWord32(buffer, pos, report_block.Jitter);
-  AssignUWord32(buffer, pos, report_block.LastSR);
-  AssignUWord32(buffer, pos, report_block.DelayLastSR);
+void CreateReportBlocks(const std::vector<RTCPPacketReportBlockItem>& blocks,
+                        uint8_t* buffer,
+                        size_t* pos) {
+  for (std::vector<RTCPPacketReportBlockItem>::const_iterator
+       it = blocks.begin(); it != blocks.end(); ++it) {
+    AssignUWord32(buffer, pos, (*it).SSRC);
+    AssignUWord8(buffer, pos, (*it).FractionLost);
+    AssignUWord24(buffer, pos, (*it).CumulativeNumOfPacketsLost);
+    AssignUWord32(buffer, pos, (*it).ExtendedHighestSequenceNumber);
+    AssignUWord32(buffer, pos, (*it).Jitter);
+    AssignUWord32(buffer, pos, (*it).LastSR);
+    AssignUWord32(buffer, pos, (*it).DelayLastSR);
+  }
+}
+
+// Transmission Time Offsets in RTP Streams (RFC 5450).
+//
+//      0                   1                   2                   3
+//      0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+//     +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+// hdr |V=2|P|    RC   |   PT=IJ=195   |             length            |
+//     +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+//     |                      inter-arrival jitter                     |
+//     +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+//     .                                                               .
+//     .                                                               .
+//     .                                                               .
+//     |                      inter-arrival jitter                     |
+//     +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+
+void CreateIj(const std::vector<uint32_t>& ij_items,
+              uint8_t* buffer,
+              size_t* pos) {
+  size_t length = ij_items.size();
+  CreateHeader(length, PT_IJ, length, buffer, pos);
+  for (std::vector<uint32_t>::const_iterator it = ij_items.begin();
+       it != ij_items.end(); ++it) {
+    AssignUWord32(buffer, pos, *it);
+  }
+}
+
+// Source Description (SDES) (RFC 3550).
+//
+//         0                   1                   2                   3
+//         0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+//        +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+// header |V=2|P|    SC   |  PT=SDES=202  |             length            |
+//        +=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+
+// chunk  |                          SSRC/CSRC_1                          |
+//   1    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+//        |                           SDES items                          |
+//        |                              ...                              |
+//        +=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+
+// chunk  |                          SSRC/CSRC_2                          |
+//   2    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+//        |                           SDES items                          |
+//        |                              ...                              |
+//        +=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+
+//
+// Canonical End-Point Identifier SDES Item (CNAME)
+//
+//    0                   1                   2                   3
+//    0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+//   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+//   |    CNAME=1    |     length    | user and domain name        ...
+//   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+
+void CreateSdes(const std::vector<Sdes::Chunk>& chunks,
+                size_t length,
+                uint8_t* buffer,
+                size_t* pos) {
+  CreateHeader(chunks.size(), PT_SDES, length, buffer, pos);
+  const uint8_t kSdesItemType = 1;
+  for (std::vector<Sdes::Chunk>::const_iterator it = chunks.begin();
+       it != chunks.end(); ++it) {
+    AssignUWord32(buffer, pos, (*it).ssrc);
+    AssignUWord8(buffer, pos, kSdesItemType);
+    AssignUWord8(buffer, pos, (*it).name.length());
+    memcpy(buffer + *pos, (*it).name.data(), (*it).name.length());
+    *pos += (*it).name.length();
+    memset(buffer + *pos, 0, (*it).null_octets);
+    *pos += (*it).null_octets;
+  }
 }
 
 // Bye packet (BYE) (RFC 3550).
@@ -171,9 +263,9 @@
 
 void CreateBye(const RTCPPacketBYE& bye,
                const std::vector<uint32_t>& csrcs,
-               uint16_t length,
+               size_t length,
                uint8_t* buffer,
-               uint16_t* pos) {
+               size_t* pos) {
   CreateHeader(length, PT_BYE, length, buffer, pos);
   AssignUWord32(buffer, pos, bye.SenderSSRC);
   for (std::vector<uint32_t>::const_iterator it = csrcs.begin();
@@ -182,6 +274,32 @@
   }
 }
 
+// Application-Defined packet (APP) (RFC 3550).
+//
+//   0                   1                   2                   3
+//   0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+//  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+//  |V=2|P| subtype |   PT=APP=204  |             length            |
+//  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+//  |                           SSRC/CSRC                           |
+//  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+//  |                          name (ASCII)                         |
+//  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+//  |                   application-dependent data                ...
+//  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+
+void CreateApp(const RTCPPacketAPP& app,
+               uint32_t ssrc,
+               size_t length,
+               uint8_t* buffer,
+               size_t* pos) {
+  CreateHeader(app.SubType, PT_APP, length, buffer, pos);
+  AssignUWord32(buffer, pos, ssrc);
+  AssignUWord32(buffer, pos, app.Name);
+  memcpy(buffer + *pos, app.Data, app.Size);
+  *pos += app.Size;
+}
+
 // RFC 4585: Feedback format.
 //
 // Common packet format:
@@ -199,6 +317,47 @@
 //   :
 //
 
+// Picture loss indication (PLI) (RFC 4585).
+//
+// FCI: no feedback control information.
+
+void CreatePli(const RTCPPacketPSFBPLI& pli,
+               size_t length,
+               uint8_t* buffer,
+               size_t* pos) {
+  const uint8_t kFmt = 1;
+  CreateHeader(kFmt, PT_PSFB, length, buffer, pos);
+  AssignUWord32(buffer, pos, pli.SenderSSRC);
+  AssignUWord32(buffer, pos, pli.MediaSSRC);
+}
+
+// Slice loss indication (SLI) (RFC 4585).
+//
+// FCI:
+//
+//    0                   1                   2                   3
+//    0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+//   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+//   |            First        |        Number           | PictureID |
+//   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+
+void CreateSli(const RTCPPacketPSFBSLI& sli,
+               const RTCPPacketPSFBSLIItem& sli_item,
+               size_t length,
+               uint8_t* buffer,
+               size_t* pos) {
+  const uint8_t kFmt = 2;
+  CreateHeader(kFmt, PT_PSFB, length, buffer, pos);
+  AssignUWord32(buffer, pos, sli.SenderSSRC);
+  AssignUWord32(buffer, pos, sli.MediaSSRC);
+
+  AssignUWord8(buffer, pos, sli_item.FirstMB >> 5);
+  AssignUWord8(buffer, pos, (sli_item.FirstMB << 3) +
+                            ((sli_item.NumberOfMB >> 10) & 0x07));
+  AssignUWord8(buffer, pos, sli_item.NumberOfMB >> 2);
+  AssignUWord8(buffer, pos, (sli_item.NumberOfMB << 6) + sli_item.PictureId);
+}
+
 // Generic NACK (RFC 4585).
 //
 // FCI:
@@ -211,9 +370,9 @@
 
 void CreateNack(const RTCPPacketRTPFBNACK& nack,
                 const std::vector<RTCPPacketRTPFBNACKItem>& nack_fields,
-                uint16_t length,
+                size_t length,
                 uint8_t* buffer,
-                uint16_t* pos) {
+                size_t* pos) {
   const uint8_t kFmt = 1;
   CreateHeader(kFmt, PT_RTPFB, length, buffer, pos);
   AssignUWord32(buffer, pos, nack.SenderSSRC);
@@ -239,9 +398,9 @@
 
 void CreateRpsi(const RTCPPacketPSFBRPSI& rpsi,
                 uint8_t padding_bytes,
-                uint16_t length,
+                size_t length,
                 uint8_t* buffer,
-                uint16_t* pos) {
+                size_t* pos) {
   // Native bit string should be a multiple of 8 bits.
   assert(rpsi.NumberOfValidBits % 8 == 0);
   const uint8_t kFmt = 3;
@@ -270,9 +429,9 @@
 
 void CreateFir(const RTCPPacketPSFBFIR& fir,
                const RTCPPacketPSFBFIRItem& fir_item,
-               uint16_t length,
+               size_t length,
                uint8_t* buffer,
-               uint16_t* pos) {
+               size_t* pos) {
   const uint8_t kFmt = 4;
   CreateHeader(kFmt, PT_PSFB, length, buffer, pos);
   AssignUWord32(buffer, pos, fir.SenderSSRC);
@@ -281,16 +440,6 @@
   AssignUWord8(buffer, pos, fir_item.CommandSequenceNumber);
   AssignUWord24(buffer, pos, 0);
 }
-
-template <typename T>
-void AppendBlocks(const std::vector<T*>& blocks,
-                  uint8_t* buffer,
-                  uint16_t* pos) {
-  for (typename std::vector<T*>::const_iterator it = blocks.begin();
-       it != blocks.end(); ++it) {
-    (*it)->Create(buffer, pos);
-  }
-}
 }  // namespace
 
 void RtcpPacket::Append(RtcpPacket* packet) {
@@ -299,39 +448,41 @@
 }
 
 RawPacket RtcpPacket::Build() const {
-  uint16_t len = 0;
+  size_t length = 0;
   uint8_t packet[IP_PACKET_SIZE];
-  CreateAndAddAppended(packet, &len, IP_PACKET_SIZE);
-  return RawPacket(packet, len);
+  CreateAndAddAppended(packet, &length, IP_PACKET_SIZE);
+  return RawPacket(packet, length);
 }
 
-void RtcpPacket::Build(uint8_t* packet, uint16_t* len, uint16_t max_len) const {
-  *len = 0;
-  CreateAndAddAppended(packet, len, max_len);
+void RtcpPacket::Build(uint8_t* packet,
+                       size_t* length,
+                       size_t max_length) const {
+  *length = 0;
+  CreateAndAddAppended(packet, length, max_length);
 }
 
 void RtcpPacket::CreateAndAddAppended(uint8_t* packet,
-                                      uint16_t* len,
-                                      uint16_t max_len) const {
-  Create(packet, len, max_len);
+                                      size_t* length,
+                                      size_t max_length) const {
+  Create(packet, length, max_length);
   for (std::vector<RtcpPacket*>::const_iterator it = appended_packets_.begin();
       it != appended_packets_.end(); ++it) {
-    (*it)->CreateAndAddAppended(packet, len, max_len);
+    (*it)->CreateAndAddAppended(packet, length, max_length);
   }
 }
 
-void Empty::Create(uint8_t* packet, uint16_t* len, uint16_t max_len) const {
+void Empty::Create(uint8_t* packet, size_t* length, size_t max_length) const {
 }
 
 void SenderReport::Create(uint8_t* packet,
-                          uint16_t* len,
-                          uint16_t max_len) const {
-  if (*len + Length() > max_len) {
+                          size_t* length,
+                          size_t max_length) const {
+  if (*length + BlockLength() > max_length) {
     LOG(LS_WARNING) << "Max packet size reached.";
     return;
   }
-  CreateSenderReport(sr_, BlockToHeaderLength(Length()), packet, len);
-  AppendBlocks(report_blocks_, packet, len);
+  CreateSenderReport(sr_, BlockToHeaderLength(BlockLength()), packet, length);
+  CreateReportBlocks(report_blocks_, packet, length);
 }
 
 void SenderReport::WithReportBlock(ReportBlock* block) {
@@ -340,19 +491,19 @@
     LOG(LS_WARNING) << "Max report blocks reached.";
     return;
   }
-  report_blocks_.push_back(block);
+  report_blocks_.push_back(block->report_block_);
   sr_.NumberOfReportBlocks = report_blocks_.size();
 }
 
 void ReceiverReport::Create(uint8_t* packet,
-                            uint16_t* len,
-                            uint16_t max_len) const {
-  if (*len + Length() > max_len) {
+                            size_t* length,
+                            size_t max_length) const {
+  if (*length + BlockLength() > max_length) {
     LOG(LS_WARNING) << "Max packet size reached.";
     return;
   }
-  CreateReceiverReport(rr_, BlockToHeaderLength(Length()), packet, len);
-  AppendBlocks(report_blocks_, packet, len);
+  CreateReceiverReport(rr_, BlockToHeaderLength(BlockLength()), packet, length);
+  CreateReportBlocks(report_blocks_, packet, length);
 }
 
 void ReceiverReport::WithReportBlock(ReportBlock* block) {
@@ -361,20 +512,71 @@
     LOG(LS_WARNING) << "Max report blocks reached.";
     return;
   }
-  report_blocks_.push_back(block);
+  report_blocks_.push_back(block->report_block_);
   rr_.NumberOfReportBlocks = report_blocks_.size();
 }
 
-void ReportBlock::Create(uint8_t* packet, uint16_t* len) const {
-  CreateReportBlock(report_block_, packet, len);
-}
-
-void Bye::Create(uint8_t* packet, uint16_t* len, uint16_t max_len) const {
-  if (*len + Length() > max_len) {
+void Ij::Create(uint8_t* packet, size_t* length, size_t max_length) const {
+  if (*length + BlockLength() > max_length) {
     LOG(LS_WARNING) << "Max packet size reached.";
     return;
   }
-  CreateBye(bye_, csrcs_, BlockToHeaderLength(Length()), packet, len);
+  CreateIj(ij_items_, packet, length);
+}
+
+void Ij::WithJitterItem(uint32_t jitter) {
+  if (ij_items_.size() >= kMaxNumberOfIjItems) {
+    LOG(LS_WARNING) << "Max inter-arrival jitter items reached.";
+    return;
+  }
+  ij_items_.push_back(jitter);
+}
+
+void Sdes::Create(uint8_t* packet, size_t* length, size_t max_length) const {
+  assert(!chunks_.empty());
+  if (*length + BlockLength() > max_length) {
+    LOG(LS_WARNING) << "Max packet size reached.";
+    return;
+  }
+  CreateSdes(chunks_, BlockToHeaderLength(BlockLength()), packet, length);
+}
+
+void Sdes::WithCName(uint32_t ssrc, std::string cname) {
+  assert(cname.length() <= 0xff);
+  if (chunks_.size() >= kMaxNumberOfChunks) {
+    LOG(LS_WARNING) << "Max SDES chunks reached.";
+    return;
+  }
+  // In each chunk, the list of items must be terminated by one or more null
+  // octets. The next chunk must start on a 32-bit boundary.
+  // CNAME (1 byte) | length (1 byte) | name | padding.
+  int null_octets = 4 - ((2 + cname.length()) % 4);
+  Chunk chunk;
+  chunk.ssrc = ssrc;
+  chunk.name = cname;
+  chunk.null_octets = null_octets;
+  chunks_.push_back(chunk);
+}
+
+size_t Sdes::BlockLength() const {
+  // Header (4 bytes).
+  // Chunk:
+  // SSRC/CSRC (4 bytes) | CNAME (1 byte) | length (1 byte) | name | padding.
+  size_t length = kHeaderLength;
+  for (std::vector<Chunk>::const_iterator it = chunks_.begin();
+       it != chunks_.end(); ++it) {
+    length += 6 + (*it).name.length() + (*it).null_octets;
+  }
+  assert(length % 4 == 0);
+  return length;
+}
+
+void Bye::Create(uint8_t* packet, size_t* length, size_t max_length) const {
+  if (*length + BlockLength() > max_length) {
+    LOG(LS_WARNING) << "Max packet size reached.";
+    return;
+  }
+  CreateBye(bye_, csrcs_, BlockToHeaderLength(BlockLength()), packet, length);
 }
 
 void Bye::WithCsrc(uint32_t csrc) {
@@ -385,13 +587,39 @@
   csrcs_.push_back(csrc);
 }
 
-void Nack::Create(uint8_t* packet, uint16_t* len, uint16_t max_len) const {
-  assert(!nack_fields_.empty());
-  if (*len + Length() > max_len) {
+void App::Create(uint8_t* packet, size_t* length, size_t max_length) const {
+  if (*length + BlockLength() > max_length) {
     LOG(LS_WARNING) << "Max packet size reached.";
     return;
   }
-  CreateNack(nack_, nack_fields_, BlockToHeaderLength(Length()), packet, len);
+  CreateApp(app_, ssrc_, BlockToHeaderLength(BlockLength()), packet, length);
+}
+
+void Pli::Create(uint8_t* packet, size_t* length, size_t max_length) const {
+  if (*length + BlockLength() > max_length) {
+    LOG(LS_WARNING) << "Max packet size reached.";
+    return;
+  }
+  CreatePli(pli_, BlockToHeaderLength(BlockLength()), packet, length);
+}
+
+void Sli::Create(uint8_t* packet, size_t* length, size_t max_length) const {
+  if (*length + BlockLength() > max_length) {
+    LOG(LS_WARNING) << "Max packet size reached.";
+    return;
+  }
+  CreateSli(sli_, sli_item_, BlockToHeaderLength(BlockLength()), packet,
+            length);
+}
+
+void Nack::Create(uint8_t* packet, size_t* length, size_t max_length) const {
+  assert(!nack_fields_.empty());
+  if (*length + BlockLength() > max_length) {
+    LOG(LS_WARNING) << "Max packet size reached.";
+    return;
+  }
+  CreateNack(nack_, nack_fields_, BlockToHeaderLength(BlockLength()), packet,
+             length);
 }
 
 void Nack::WithList(const uint16_t* nack_list, int length) {
@@ -418,13 +646,14 @@
   }
 }
 
-void Rpsi::Create(uint8_t* packet, uint16_t* len, uint16_t max_len) const {
+void Rpsi::Create(uint8_t* packet, size_t* length, size_t max_length) const {
   assert(rpsi_.NumberOfValidBits > 0);
-  if (*len + Length() > max_len) {
+  if (*length + BlockLength() > max_length) {
     LOG(LS_WARNING) << "Max packet size reached.";
     return;
   }
-  CreateRpsi(rpsi_, padding_bytes_, BlockToHeaderLength(Length()), packet, len);
+  CreateRpsi(rpsi_, padding_bytes_, BlockToHeaderLength(BlockLength()), packet,
+             length);
 }
 
 void Rpsi::WithPictureId(uint64_t picture_id) {
@@ -454,12 +683,13 @@
   }
 }
 
-void Fir::Create(uint8_t* packet, uint16_t* len, uint16_t max_len) const {
-  if (*len + Length() > max_len) {
+void Fir::Create(uint8_t* packet, size_t* length, size_t max_length) const {
+  if (*length + BlockLength() > max_length) {
     LOG(LS_WARNING) << "Max packet size reached.";
     return;
   }
-  CreateFir(fir_, fir_item_, BlockToHeaderLength(Length()), packet, len);
+  CreateFir(fir_, fir_item_, BlockToHeaderLength(BlockLength()), packet,
+            length);
 }
 }  // namespace rtcp
 }  // namespace webrtc
diff --git a/webrtc/modules/rtp_rtcp/source/rtcp_packet.h b/webrtc/modules/rtp_rtcp/source/rtcp_packet.h
index 641bd7f..f60e848 100644
--- a/webrtc/modules/rtp_rtcp/source/rtcp_packet.h
+++ b/webrtc/modules/rtp_rtcp/source/rtcp_packet.h
@@ -12,6 +12,8 @@
 #ifndef WEBRTC_MODULES_RTP_RTCP_RTCP_PACKET_H_
 #define WEBRTC_MODULES_RTP_RTCP_RTCP_PACKET_H_
 
+#include <map>
+#include <string>
 #include <vector>
 
 #include "webrtc/modules/rtp_rtcp/source/rtcp_utility.h"
@@ -21,8 +23,10 @@
 namespace webrtc {
 namespace rtcp {
 
+enum { kCommonFbFmtLength = 12 };
+enum { kReportBlockLength = 24 };
+
 class RawPacket;
-class ReportBlock;
 
 // Class for building RTCP packets.
 //
@@ -40,9 +44,9 @@
 //  fir.To(234)
 //  fir.WithCommandSeqNum(123);
 //
-//  uint16_t len = 0;                      // Builds an intra frame request
+//  size_t length = 0;                     // Builds an intra frame request
 //  uint8_t packet[kPacketSize];           // with sequence number 123.
-//  fir.Build(packet, &len, kPacketSize);
+//  fir.Build(packet, &length, kPacketSize);
 //
 //  RawPacket packet = fir.Build();        // Returns a RawPacket holding
 //                                         // the built rtcp packet.
@@ -59,18 +63,20 @@
 
   RawPacket Build() const;
 
-  void Build(uint8_t* packet, uint16_t* len, uint16_t max_len) const;
+  void Build(uint8_t* packet, size_t* length, size_t max_length) const;
 
  protected:
-  RtcpPacket() {}
+  RtcpPacket() : kHeaderLength(4) {}
 
   virtual void Create(
-      uint8_t* packet, uint16_t* len, uint16_t max_len) const = 0;
+      uint8_t* packet, size_t* length, size_t max_length) const = 0;
 
-  void CreateAndAddAppended(
-      uint8_t* packet, uint16_t* len, uint16_t max_len) const;
+  const size_t kHeaderLength;
 
  private:
+  void CreateAndAddAppended(
+      uint8_t* packet, size_t* length, size_t max_length) const;
+
   std::vector<RtcpPacket*> appended_packets_;
 };
 
@@ -81,11 +87,66 @@
   virtual ~Empty() {}
 
  protected:
-  virtual void Create(uint8_t* packet, uint16_t* len, uint16_t max_len) const;
+  virtual void Create(uint8_t* packet, size_t* length, size_t max_length) const;
 };
 
-//// From RFC 3550, RTP: A Transport Protocol for Real-Time Applications.
+// From RFC 3550, RTP: A Transport Protocol for Real-Time Applications.
 //
+// RTCP report block (RFC 3550).
+//
+//   0                   1                   2                   3
+//   0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+//  +=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+
+//  |                 SSRC_1 (SSRC of first source)                 |
+//  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+//  | fraction lost |       cumulative number of packets lost       |
+//  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+//  |           extended highest sequence number received           |
+//  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+//  |                      interarrival jitter                      |
+//  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+//  |                         last SR (LSR)                         |
+//  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+//  |                   delay since last SR (DLSR)                  |
+//  +=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+
+
+class ReportBlock {
+ public:
+  ReportBlock() {
+    // TODO(asapersson): Consider adding a constructor to struct.
+    memset(&report_block_, 0, sizeof(report_block_));
+  }
+
+  ~ReportBlock() {}
+
+  void To(uint32_t ssrc) {
+    report_block_.SSRC = ssrc;
+  }
+  void WithFractionLost(uint8_t fraction_lost) {
+    report_block_.FractionLost = fraction_lost;
+  }
+  void WithCumulativeLost(uint32_t cumulative_lost) {
+    report_block_.CumulativeNumOfPacketsLost = cumulative_lost;
+  }
+  void WithExtHighestSeqNum(uint32_t ext_highest_seq_num) {
+    report_block_.ExtendedHighestSequenceNumber = ext_highest_seq_num;
+  }
+  void WithJitter(uint32_t jitter) {
+    report_block_.Jitter = jitter;
+  }
+  void WithLastSr(uint32_t last_sr) {
+    report_block_.LastSR = last_sr;
+  }
+  void WithDelayLastSr(uint32_t delay_last_sr) {
+    report_block_.DelayLastSR = delay_last_sr;
+  }
+
+ private:
+  friend class SenderReport;
+  friend class ReceiverReport;
+  RTCPUtility::RTCPPacketReportBlockItem report_block_;
+};
+
 // RTCP sender report (RFC 3550).
 //
 //   0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
@@ -109,8 +170,7 @@
 
 class SenderReport : public RtcpPacket {
  public:
-  SenderReport()
-    : RtcpPacket() {
+  SenderReport() : RtcpPacket() {
     memset(&sr_, 0, sizeof(sr_));
   }
 
@@ -136,20 +196,22 @@
   }
   void WithReportBlock(ReportBlock* block);
 
-  enum { kMaxNumberOfReportBlocks = 0x1f };
-
  protected:
-  virtual void Create(uint8_t* packet, uint16_t* len, uint16_t max_len) const;
+  virtual void Create(
+      uint8_t* packet, size_t* length, size_t max_length) const OVERRIDE;
 
  private:
-  uint16_t Length() const {
-    const uint16_t kSrBlockLen = 28;
-    const uint16_t kReportBlockLen = 24;
-    return kSrBlockLen + report_blocks_.size() * kReportBlockLen;
+  enum { kMaxNumberOfReportBlocks = 0x1f };
+
+  size_t BlockLength() const {
+    const size_t kSrHeaderLength = 8;
+    const size_t kSenderInfoLength = 20;
+    return kSrHeaderLength + kSenderInfoLength +
+           report_blocks_.size() * kReportBlockLength;
   }
 
   RTCPUtility::RTCPPacketSR sr_;
-  std::vector<ReportBlock*> report_blocks_;
+  std::vector<RTCPUtility::RTCPPacketReportBlockItem> report_blocks_;
 };
 
 //
@@ -167,8 +229,7 @@
 
 class ReceiverReport : public RtcpPacket {
  public:
-  ReceiverReport()
-    : RtcpPacket() {
+  ReceiverReport() : RtcpPacket() {
     memset(&rr_, 0, sizeof(rr_));
   }
 
@@ -179,75 +240,117 @@
   }
   void WithReportBlock(ReportBlock* block);
 
-  enum { kMaxNumberOfReportBlocks = 0x1f };
-
  protected:
-  virtual void Create(uint8_t* packet, uint16_t* len, uint16_t max_len) const;
+  virtual void Create(
+      uint8_t* packet, size_t* length, size_t max_length) const OVERRIDE;
 
  private:
-  uint16_t Length() const {
-    const uint16_t kRrBlockLen = 8;
-    const uint16_t kReportBlockLen = 24;
-    return kRrBlockLen + report_blocks_.size() * kReportBlockLen;
+  enum { kMaxNumberOfReportBlocks = 0x1f };
+
+  size_t BlockLength() const {
+    const size_t kRrHeaderLength = 8;
+    return kRrHeaderLength + report_blocks_.size() * kReportBlockLength;
   }
 
   RTCPUtility::RTCPPacketRR rr_;
-  std::vector<ReportBlock*> report_blocks_;
+  std::vector<RTCPUtility::RTCPPacketReportBlockItem> report_blocks_;
 };
 
+// Transmission Time Offsets in RTP Streams (RFC 5450).
 //
-// RTCP report block (RFC 3550).
+//      0                   1                   2                   3
+//      0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+//     +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+// hdr |V=2|P|    RC   |   PT=IJ=195   |             length            |
+//     +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+//     |                      inter-arrival jitter                     |
+//     +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+//     .                                                               .
+//     .                                                               .
+//     .                                                               .
+//     |                      inter-arrival jitter                     |
+//     +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
 //
-//   0                   1                   2                   3
-//   0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
-//  +=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+
-//  |                 SSRC_1 (SSRC of first source)                 |
-//  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
-//  | fraction lost |       cumulative number of packets lost       |
-//  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
-//  |           extended highest sequence number received           |
-//  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
-//  |                      interarrival jitter                      |
-//  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
-//  |                         last SR (LSR)                         |
-//  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
-//  |                   delay since last SR (DLSR)                  |
-//  +=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+
+//  If present, this RTCP packet must be placed after a receiver report
+//  (inside a compound RTCP packet), and MUST have the same value for RC
+//  (reception report count) as the receiver report.
 
-class ReportBlock {
+class Ij : public RtcpPacket {
  public:
-  ReportBlock() {
-    memset(&report_block_, 0, sizeof(report_block_));
-  }
+  Ij() : RtcpPacket() {}
 
-  ~ReportBlock() {}
+  virtual ~Ij() {}
 
-  void To(uint32_t ssrc) {
-    report_block_.SSRC = ssrc;
-  }
-  void WithFractionLost(uint8_t fraction_lost) {
-    report_block_.FractionLost = fraction_lost;
-  }
-  void WithCumPacketsLost(uint32_t cum_packets_lost) {
-    report_block_.CumulativeNumOfPacketsLost = cum_packets_lost;
-  }
-  void WithExtHighestSeqNum(uint32_t ext_highest_seq_num) {
-    report_block_.ExtendedHighestSequenceNumber = ext_highest_seq_num;
-  }
-  void WithJitter(uint32_t jitter) {
-    report_block_.Jitter = jitter;
-  }
-  void WithLastSr(uint32_t last_sr) {
-    report_block_.LastSR = last_sr;
-  }
-  void WithDelayLastSr(uint32_t delay_last_sr) {
-    report_block_.DelayLastSR = delay_last_sr;
-  }
+  void WithJitterItem(uint32_t jitter);
 
-  void Create(uint8_t* packet, uint16_t* len) const;
+ protected:
+  virtual void Create(
+      uint8_t* packet, size_t* length, size_t max_length) const OVERRIDE;
 
  private:
-  RTCPUtility::RTCPPacketReportBlockItem report_block_;
+  enum { kMaxNumberOfIjItems = 0x1f };
+
+  size_t BlockLength() const {
+    return kHeaderLength + 4 * ij_items_.size();
+  }
+
+  std::vector<uint32_t> ij_items_;
+
+  DISALLOW_COPY_AND_ASSIGN(Ij);
+};
+
+// Source Description (SDES) (RFC 3550).
+//
+//         0                   1                   2                   3
+//         0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+//        +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+// header |V=2|P|    SC   |  PT=SDES=202  |             length            |
+//        +=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+
+// chunk  |                          SSRC/CSRC_1                          |
+//   1    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+//        |                           SDES items                          |
+//        |                              ...                              |
+//        +=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+
+// chunk  |                          SSRC/CSRC_2                          |
+//   2    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+//        |                           SDES items                          |
+//        |                              ...                              |
+//        +=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+
+//
+// Canonical End-Point Identifier SDES Item (CNAME)
+//
+//    0                   1                   2                   3
+//    0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+//   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+//   |    CNAME=1    |     length    | user and domain name        ...
+//   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+
+class Sdes : public RtcpPacket {
+ public:
+  Sdes() : RtcpPacket() {}
+
+  virtual ~Sdes() {}
+
+  void WithCName(uint32_t ssrc, std::string cname);
+
+  struct Chunk {
+    uint32_t ssrc;
+    std::string name;
+    int null_octets;
+  };
+
+ protected:
+  virtual void Create(
+      uint8_t* packet, size_t* length, size_t max_length) const OVERRIDE;
+
+ private:
+  enum { kMaxNumberOfChunks = 0x1f };
+
+  size_t BlockLength() const;
+
+  std::vector<Chunk> chunks_;
+
+  DISALLOW_COPY_AND_ASSIGN(Sdes);
 };
 
 //
@@ -266,8 +369,7 @@
 
 class Bye : public RtcpPacket {
  public:
-  Bye()
-    : RtcpPacket() {
+  Bye() : RtcpPacket() {
     memset(&bye_, 0, sizeof(bye_));
   }
 
@@ -278,21 +380,79 @@
   }
   void WithCsrc(uint32_t csrc);
 
-  enum { kMaxNumberOfCsrcs = 0x1f - 1 };
-
  protected:
-  virtual void Create(uint8_t* packet, uint16_t* len, uint16_t max_len) const;
+  virtual void Create(
+      uint8_t* packet, size_t* length, size_t max_length) const OVERRIDE;
 
  private:
-  uint16_t Length() const {
-    const uint16_t kByeBlockLen = 8 + 4 * csrcs_.size();
-    return kByeBlockLen;
+  enum { kMaxNumberOfCsrcs = 0x1f - 1 };
+
+  size_t BlockLength() const {
+    size_t source_count = 1 + csrcs_.size();
+    return kHeaderLength + 4 * source_count;
   }
 
   RTCPUtility::RTCPPacketBYE bye_;
   std::vector<uint32_t> csrcs_;
 };
 
+// Application-Defined packet (APP) (RFC 3550).
+//
+//   0                   1                   2                   3
+//   0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+//  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+//  |V=2|P| subtype |   PT=APP=204  |             length            |
+//  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+//  |                           SSRC/CSRC                           |
+//  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+//  |                          name (ASCII)                         |
+//  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+//  |                   application-dependent data                ...
+//  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+
+class App : public RtcpPacket {
+ public:
+  App()
+      : RtcpPacket(),
+        ssrc_(0) {
+    memset(&app_, 0, sizeof(app_));
+  }
+
+  virtual ~App() {}
+
+  void From(uint32_t ssrc) {
+    ssrc_ = ssrc;
+  }
+  void WithSubType(uint8_t subtype) {
+    assert(subtype <= 0x1f);
+    app_.SubType = subtype;
+  }
+  void WithName(uint32_t name) {
+    app_.Name = name;
+  }
+  void WithData(const uint8_t* data, uint16_t data_length) {
+    assert(data);
+    assert(data_length <= kRtcpAppCode_DATA_SIZE);
+    assert(data_length % 4 == 0);
+    memcpy(app_.Data, data, data_length);
+    app_.Size = data_length;
+  }
+
+ protected:
+  virtual void Create(
+      uint8_t* packet, size_t* length, size_t max_length) const OVERRIDE;
+
+ private:
+  size_t BlockLength() const {
+    return 12 + app_.Size;
+  }
+
+  uint32_t ssrc_;
+  RTCPUtility::RTCPPacketAPP app_;
+
+  DISALLOW_COPY_AND_ASSIGN(App);
+};
+
 // RFC 4585: Feedback format.
 //
 // Common packet format:
@@ -309,6 +469,92 @@
 //   :            Feedback Control Information (FCI)                 :
 //   :
 
+// Picture loss indication (PLI) (RFC 4585).
+//
+// FCI: no feedback control information.
+
+class Pli : public RtcpPacket {
+ public:
+  Pli() : RtcpPacket() {
+    memset(&pli_, 0, sizeof(pli_));
+  }
+
+  virtual ~Pli() {}
+
+  void From(uint32_t ssrc) {
+    pli_.SenderSSRC = ssrc;
+  }
+  void To(uint32_t ssrc) {
+    pli_.MediaSSRC = ssrc;
+  }
+
+ protected:
+  virtual void Create(
+      uint8_t* packet, size_t* length, size_t max_length) const OVERRIDE;
+
+ private:
+  size_t BlockLength() const {
+    return kCommonFbFmtLength;
+  }
+
+  RTCPUtility::RTCPPacketPSFBPLI pli_;
+
+  DISALLOW_COPY_AND_ASSIGN(Pli);
+};
+
+// Slice loss indication (SLI) (RFC 4585).
+//
+// FCI:
+//    0                   1                   2                   3
+//    0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+//   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+//   |            First        |        Number           | PictureID |
+//   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+
+class Sli : public RtcpPacket {
+ public:
+  Sli() : RtcpPacket() {
+    memset(&sli_, 0, sizeof(sli_));
+    memset(&sli_item_, 0, sizeof(sli_item_));
+  }
+
+  virtual ~Sli() {}
+
+  void From(uint32_t ssrc) {
+    sli_.SenderSSRC = ssrc;
+  }
+  void To(uint32_t ssrc) {
+    sli_.MediaSSRC = ssrc;
+  }
+  void WithFirstMb(uint16_t first_mb) {
+    assert(first_mb <= 0x1fff);
+    sli_item_.FirstMB = first_mb;
+  }
+  void WithNumberOfMb(uint16_t number_mb) {
+    assert(number_mb <= 0x1fff);
+    sli_item_.NumberOfMB = number_mb;
+  }
+  void WithPictureId(uint8_t picture_id) {
+    assert(picture_id <= 0x3f);
+    sli_item_.PictureId = picture_id;
+  }
+
+ protected:
+  virtual void Create(
+      uint8_t* packet, size_t* length, size_t max_length) const OVERRIDE;
+
+ private:
+  size_t BlockLength() const {
+    const size_t kFciLength = 4;
+    return kCommonFbFmtLength + kFciLength;
+  }
+
+  RTCPUtility::RTCPPacketPSFBSLI sli_;
+  RTCPUtility::RTCPPacketPSFBSLIItem sli_item_;
+
+  DISALLOW_COPY_AND_ASSIGN(Sli);
+};
+
 // Generic NACK (RFC 4585).
 //
 // FCI:
@@ -320,8 +566,7 @@
 
 class Nack : public RtcpPacket {
  public:
-  Nack()
-    : RtcpPacket() {
+  Nack() : RtcpPacket() {
     memset(&nack_, 0, sizeof(nack_));
   }
 
@@ -336,13 +581,13 @@
   void WithList(const uint16_t* nack_list, int length);
 
  protected:
-  virtual void Create(uint8_t* packet, uint16_t* len, uint16_t max_len) const
-      OVERRIDE;
+  virtual void Create(
+      uint8_t* packet, size_t* length, size_t max_length) const OVERRIDE;
 
  private:
-  uint16_t Length() const {
-    const uint16_t kNackBlockLen = 4 * (3 + nack_fields_.size());
-    return kNackBlockLen;
+  size_t BlockLength() const {
+    size_t fci_length = 4 * nack_fields_.size();
+    return kCommonFbFmtLength + fci_length;
   }
 
   RTCPUtility::RTCPPacketRTPFBNACK nack_;
@@ -366,8 +611,8 @@
 class Rpsi : public RtcpPacket {
  public:
   Rpsi()
-    : RtcpPacket(),
-      padding_bytes_(0) {
+      : RtcpPacket(),
+        padding_bytes_(0) {
     memset(&rpsi_, 0, sizeof(rpsi_));
   }
 
@@ -386,14 +631,13 @@
   void WithPictureId(uint64_t picture_id);
 
  protected:
-  virtual void Create(uint8_t* packet, uint16_t* len, uint16_t max_len) const
-      OVERRIDE;
+  virtual void Create(
+      uint8_t* packet, size_t* length, size_t max_length) const OVERRIDE;
 
  private:
-  uint16_t Length() const {
-    const uint16_t kRpsiBlockLen =
-        12 + 2 + (rpsi_.NumberOfValidBits / 8) + padding_bytes_;
-    return kRpsiBlockLen;
+  size_t BlockLength() const {
+    size_t fci_length = 2 + (rpsi_.NumberOfValidBits / 8) + padding_bytes_;
+    return kCommonFbFmtLength + fci_length;
   }
 
   uint8_t padding_bytes_;
@@ -417,7 +661,7 @@
 class Fir : public RtcpPacket {
  public:
   Fir()
-    : RtcpPacket() {
+      : RtcpPacket() {
     memset(&fir_, 0, sizeof(fir_));
     memset(&fir_item_, 0, sizeof(fir_item_));
   }
@@ -435,12 +679,13 @@
   }
 
  protected:
-  virtual void Create(uint8_t* packet, uint16_t* len, uint16_t max_len) const;
+  virtual void Create(
+      uint8_t* packet, size_t* length, size_t max_length) const OVERRIDE;
 
  private:
-  uint16_t Length() const {
-    const uint16_t kFirBlockLen = 20;
-    return kFirBlockLen;
+  size_t BlockLength() const {
+    const size_t kFciLength = 8;
+    return kCommonFbFmtLength + kFciLength;
   }
 
   RTCPUtility::RTCPPacketPSFBFIR fir_;
@@ -450,7 +695,7 @@
 // Class holding a RTCP packet.
 //
 // Takes a built rtcp packet.
-//  RawPacket raw_packet(buffer, len);
+//  RawPacket raw_packet(buffer, length);
 //
 // To access the raw packet:
 //  raw_packet.buffer();         - pointer to the raw packet
@@ -458,22 +703,22 @@
 
 class RawPacket {
  public:
-  RawPacket(const uint8_t* buffer, uint16_t len) {
-    assert(len <= IP_PACKET_SIZE);
-    memcpy(packet_, buffer, len);
-    packet_length_ = len;
+  RawPacket(const uint8_t* packet, size_t length) {
+    assert(length <= IP_PACKET_SIZE);
+    memcpy(buffer_, packet, length);
+    buffer_length_ = length;
   }
 
   const uint8_t* buffer() {
-    return packet_;
+    return buffer_;
   }
-  uint16_t buffer_length() const {
-    return packet_length_;
+  size_t buffer_length() const {
+    return buffer_length_;
   }
 
  private:
-  uint16_t packet_length_;
-  uint8_t packet_[IP_PACKET_SIZE];
+  size_t buffer_length_;
+  uint8_t buffer_[IP_PACKET_SIZE];
 };
 
 }  // namespace rtcp
diff --git a/webrtc/modules/rtp_rtcp/source/rtcp_packet_unittest.cc b/webrtc/modules/rtp_rtcp/source/rtcp_packet_unittest.cc
index d7ae914..aa25c2e 100644
--- a/webrtc/modules/rtp_rtcp/source/rtcp_packet_unittest.cc
+++ b/webrtc/modules/rtp_rtcp/source/rtcp_packet_unittest.cc
@@ -15,16 +15,21 @@
 #include "webrtc/modules/rtp_rtcp/source/rtcp_packet.h"
 #include "webrtc/test/rtcp_packet_parser.h"
 
+using webrtc::rtcp::App;
 using webrtc::rtcp::Bye;
 using webrtc::rtcp::Empty;
 using webrtc::rtcp::Fir;
+using webrtc::rtcp::Ij;
 using webrtc::rtcp::Nack;
+using webrtc::rtcp::Pli;
+using webrtc::rtcp::Sdes;
+using webrtc::rtcp::SenderReport;
+using webrtc::rtcp::Sli;
 using webrtc::rtcp::RawPacket;
 using webrtc::rtcp::ReceiverReport;
 using webrtc::rtcp::ReportBlock;
 using webrtc::rtcp::Rpsi;
 using webrtc::test::RtcpPacketParser;
-using webrtc::rtcp::SenderReport;
 
 namespace webrtc {
 
@@ -47,7 +52,7 @@
   ReportBlock rb;
   rb.To(kRemoteSsrc);
   rb.WithFractionLost(55);
-  rb.WithCumPacketsLost(0x111111);
+  rb.WithCumulativeLost(0x111111);
   rb.WithExtHighestSeqNum(0x22222222);
   rb.WithJitter(0x33333333);
   rb.WithLastSr(0x44444444);
@@ -154,6 +159,164 @@
   EXPECT_EQ(1, parser.report_blocks_per_ssrc(kRemoteSsrc + 1));
 }
 
+TEST(RtcpPacketTest, IjNoItem) {
+  Ij ij;
+
+  RawPacket packet = ij.Build();
+  RtcpPacketParser parser;
+  parser.Parse(packet.buffer(), packet.buffer_length());
+  EXPECT_EQ(1, parser.ij()->num_packets());
+  EXPECT_EQ(0, parser.ij_item()->num_packets());
+}
+
+TEST(RtcpPacketTest, IjOneItem) {
+  Ij ij;
+  ij.WithJitterItem(0x11111111);
+
+  RawPacket packet = ij.Build();
+  RtcpPacketParser parser;
+  parser.Parse(packet.buffer(), packet.buffer_length());
+  EXPECT_EQ(1, parser.ij()->num_packets());
+  EXPECT_EQ(1, parser.ij_item()->num_packets());
+  EXPECT_EQ(0x11111111U, parser.ij_item()->Jitter());
+}
+
+TEST(RtcpPacketTest, IjTwoItems) {
+  Ij ij;
+  ij.WithJitterItem(0x11111111);
+  ij.WithJitterItem(0x22222222);
+
+  RawPacket packet = ij.Build();
+  RtcpPacketParser parser;
+  parser.Parse(packet.buffer(), packet.buffer_length());
+  EXPECT_EQ(1, parser.ij()->num_packets());
+  EXPECT_EQ(2, parser.ij_item()->num_packets());
+  EXPECT_EQ(0x22222222U, parser.ij_item()->Jitter());
+}
+
+TEST(RtcpPacketTest, AppWithNoData) {
+  App app;
+  app.WithSubType(30);
+  uint32_t name = 'n' << 24;
+  name += 'a' << 16;
+  name += 'm' << 8;
+  name += 'e';
+  app.WithName(name);
+
+  RawPacket packet = app.Build();
+  RtcpPacketParser parser;
+  parser.Parse(packet.buffer(), packet.buffer_length());
+  EXPECT_EQ(1, parser.app()->num_packets());
+  EXPECT_EQ(30U, parser.app()->SubType());
+  EXPECT_EQ(name, parser.app()->Name());
+  EXPECT_EQ(0, parser.app_item()->num_packets());
+}
+
+TEST(RtcpPacketTest, App) {
+  App app;
+  app.From(kSenderSsrc);
+  app.WithSubType(30);
+  uint32_t name = 'n' << 24;
+  name += 'a' << 16;
+  name += 'm' << 8;
+  name += 'e';
+  app.WithName(name);
+  const char kData[] = {'t', 'e', 's', 't', 'd', 'a', 't', 'a'};
+  const size_t kDataLength = sizeof(kData) / sizeof(kData[0]);
+  app.WithData((const uint8_t*)kData, kDataLength);
+
+  RawPacket packet = app.Build();
+  RtcpPacketParser parser;
+  parser.Parse(packet.buffer(), packet.buffer_length());
+  EXPECT_EQ(1, parser.app()->num_packets());
+  EXPECT_EQ(30U, parser.app()->SubType());
+  EXPECT_EQ(name, parser.app()->Name());
+  EXPECT_EQ(1, parser.app_item()->num_packets());
+  EXPECT_EQ(kDataLength, parser.app_item()->DataLength());
+  EXPECT_EQ(0, strncmp(kData, (const char*)parser.app_item()->Data(),
+      parser.app_item()->DataLength()));
+}
+
+TEST(RtcpPacketTest, SdesWithOneChunk) {
+  Sdes sdes;
+  sdes.WithCName(kSenderSsrc, "alice@host");
+
+  RawPacket packet = sdes.Build();
+  RtcpPacketParser parser;
+  parser.Parse(packet.buffer(), packet.buffer_length());
+  EXPECT_EQ(1, parser.sdes()->num_packets());
+  EXPECT_EQ(1, parser.sdes_chunk()->num_packets());
+  EXPECT_EQ(kSenderSsrc, parser.sdes_chunk()->Ssrc());
+  EXPECT_EQ("alice@host", parser.sdes_chunk()->Cname());
+}
+
+TEST(RtcpPacketTest, SdesWithMultipleChunks) {
+  Sdes sdes;
+  sdes.WithCName(kSenderSsrc, "a");
+  sdes.WithCName(kSenderSsrc + 1, "ab");
+  sdes.WithCName(kSenderSsrc + 2, "abc");
+  sdes.WithCName(kSenderSsrc + 3, "abcd");
+  sdes.WithCName(kSenderSsrc + 4, "abcde");
+  sdes.WithCName(kSenderSsrc + 5, "abcdef");
+
+  RawPacket packet = sdes.Build();
+  RtcpPacketParser parser;
+  parser.Parse(packet.buffer(), packet.buffer_length());
+  EXPECT_EQ(1, parser.sdes()->num_packets());
+  EXPECT_EQ(6, parser.sdes_chunk()->num_packets());
+  EXPECT_EQ(kSenderSsrc + 5, parser.sdes_chunk()->Ssrc());
+  EXPECT_EQ("abcdef", parser.sdes_chunk()->Cname());
+}
+
+TEST(RtcpPacketTest, CnameItemWithEmptyString) {
+  Sdes sdes;
+  sdes.WithCName(kSenderSsrc, "");
+
+  RawPacket packet = sdes.Build();
+  RtcpPacketParser parser;
+  parser.Parse(packet.buffer(), packet.buffer_length());
+  EXPECT_EQ(1, parser.sdes()->num_packets());
+  EXPECT_EQ(1, parser.sdes_chunk()->num_packets());
+  EXPECT_EQ(kSenderSsrc, parser.sdes_chunk()->Ssrc());
+  EXPECT_EQ("", parser.sdes_chunk()->Cname());
+}
+
+TEST(RtcpPacketTest, Pli) {
+  Pli pli;
+  pli.From(kSenderSsrc);
+  pli.To(kRemoteSsrc);
+
+  RawPacket packet = pli.Build();
+  RtcpPacketParser parser;
+  parser.Parse(packet.buffer(), packet.buffer_length());
+  EXPECT_EQ(1, parser.pli()->num_packets());
+  EXPECT_EQ(kSenderSsrc, parser.pli()->Ssrc());
+  EXPECT_EQ(kRemoteSsrc, parser.pli()->MediaSsrc());
+}
+
+TEST(RtcpPacketTest, Sli) {
+  const uint16_t kFirstMb = 7777;
+  const uint16_t kNumberOfMb = 6666;
+  const uint8_t kPictureId = 60;
+  Sli sli;
+  sli.From(kSenderSsrc);
+  sli.To(kRemoteSsrc);
+  sli.WithFirstMb(kFirstMb);
+  sli.WithNumberOfMb(kNumberOfMb);
+  sli.WithPictureId(kPictureId);
+
+  RawPacket packet = sli.Build();
+  RtcpPacketParser parser;
+  parser.Parse(packet.buffer(), packet.buffer_length());
+  EXPECT_EQ(1, parser.sli()->num_packets());
+  EXPECT_EQ(kSenderSsrc, parser.sli()->Ssrc());
+  EXPECT_EQ(kRemoteSsrc, parser.sli()->MediaSsrc());
+  EXPECT_EQ(1, parser.sli_item()->num_packets());
+  EXPECT_EQ(kFirstMb, parser.sli_item()->FirstMb());
+  EXPECT_EQ(kNumberOfMb, parser.sli_item()->NumberOfMb());
+  EXPECT_EQ(kPictureId, parser.sli_item()->PictureId());
+}
+
 TEST(RtcpPacketTest, Nack) {
   Nack nack;
   const uint16_t kList[] = {0, 1, 3, 8, 16};
@@ -373,11 +536,11 @@
   rr.WithReportBlock(&rb);
   rr.Append(&fir);
 
-  const uint16_t kRrLength = 8;
-  const uint16_t kReportBlockLength = 24;
-  const uint16_t kFirLength = 20;
+  const size_t kRrLength = 8;
+  const size_t kReportBlockLength = 24;
+  const size_t kFirLength = 20;
 
-  uint16_t len = 0;
+  size_t len = 0;
   uint8_t packet[kRrLength + kReportBlockLength + kFirLength];
   rr.Build(packet, &len, kRrLength + kReportBlockLength + kFirLength);
 
@@ -394,16 +557,16 @@
   rr.From(kSenderSsrc);
   rr.WithReportBlock(&rb);
 
-  const uint16_t kRrLength = 8;
-  const uint16_t kReportBlockLength = 24;
+  const size_t kRrLength = 8;
+  const size_t kReportBlockLength = 24;
 
   // No packet.
-  uint16_t len = 0;
+  size_t len = 0;
   uint8_t packet[kRrLength + kReportBlockLength - 1];
   rr.Build(packet, &len, kRrLength + kReportBlockLength - 1);
   RtcpPacketParser parser;
   parser.Parse(packet, len);
-  EXPECT_EQ(0, len);
+  EXPECT_EQ(0U, len);
 }
 
 TEST(RtcpPacketTest, BuildWithTooSmallBuffer_LastBlockFits) {
@@ -414,10 +577,10 @@
   rr.WithReportBlock(&rb);
   rr.Append(&fir);
 
-  const uint16_t kRrLength = 8;
-  const uint16_t kReportBlockLength = 24;
+  const size_t kRrLength = 8;
+  const size_t kReportBlockLength = 24;
 
-  uint16_t len = 0;
+  size_t len = 0;
   uint8_t packet[kRrLength + kReportBlockLength - 1];
   rr.Build(packet, &len, kRrLength + kReportBlockLength - 1);
   RtcpPacketParser parser;
diff --git a/webrtc/test/rtcp_packet_parser.cc b/webrtc/test/rtcp_packet_parser.cc
index 9ae8543..69c50d1 100644
--- a/webrtc/test/rtcp_packet_parser.cc
+++ b/webrtc/test/rtcp_packet_parser.cc
@@ -30,13 +30,40 @@
       case RTCPUtility::kRtcpRrCode:
         receiver_report_.Set(parser.Packet().RR);
         break;
-      case RTCPUtility::kRtcpByeCode:
-        bye_.Set(parser.Packet().BYE);
-        break;
       case RTCPUtility::kRtcpReportBlockItemCode:
         report_block_.Set(parser.Packet().ReportBlockItem);
         ++report_blocks_per_ssrc_[parser.Packet().ReportBlockItem.SSRC];
         break;
+      case RTCPUtility::kRtcpSdesCode:
+        sdes_.Set();
+        break;
+      case RTCPUtility::kRtcpSdesChunkCode:
+        sdes_chunk_.Set(parser.Packet().CName);
+        break;
+      case RTCPUtility::kRtcpByeCode:
+        bye_.Set(parser.Packet().BYE);
+        break;
+      case RTCPUtility::kRtcpAppCode:
+        app_.Set(parser.Packet().APP);
+        break;
+      case RTCPUtility::kRtcpAppItemCode:
+        app_item_.Set(parser.Packet().APP);
+        break;
+      case RTCPUtility::kRtcpExtendedIjCode:
+        ij_.Set();
+        break;
+      case RTCPUtility::kRtcpExtendedIjItemCode:
+        ij_item_.Set(parser.Packet().ExtendedJitterReportItem);
+        break;
+      case RTCPUtility::kRtcpPsfbPliCode:
+        pli_.Set(parser.Packet().PLI);
+        break;
+      case RTCPUtility::kRtcpPsfbSliCode:
+        sli_.Set(parser.Packet().SLI);
+        break;
+      case RTCPUtility::kRtcpPsfbSliItemCode:
+        sli_item_.Set(parser.Packet().SLIItem);
+        break;
       case RTCPUtility::kRtcpPsfbRpsiCode:
         rpsi_.Set(parser.Packet().RPSI);
         break;
diff --git a/webrtc/test/rtcp_packet_parser.h b/webrtc/test/rtcp_packet_parser.h
index 4db58c3..a09674f 100644
--- a/webrtc/test/rtcp_packet_parser.h
+++ b/webrtc/test/rtcp_packet_parser.h
@@ -13,6 +13,7 @@
 #define WEBRTC_TEST_RTCP_PACKET_PARSER_H_
 
 #include <map>
+#include <string>
 #include <vector>
 
 #include "webrtc/modules/rtp_rtcp/source/rtcp_utility.h"
@@ -100,6 +101,65 @@
   RTCPUtility::RTCPPacketReportBlockItem rb_;
 };
 
+class Ij : public PacketType {
+ public:
+  Ij() {}
+  virtual ~Ij() {}
+
+ private:
+  friend class RtcpPacketParser;
+
+  void Set() { ++num_packets_; }
+};
+
+class IjItem : public PacketType {
+ public:
+  IjItem() {}
+  virtual ~IjItem() {}
+
+  uint32_t Jitter() const { return ij_item_.Jitter; }
+
+ private:
+  friend class RtcpPacketParser;
+
+  void Set(const RTCPUtility::RTCPPacketExtendedJitterReportItem& ij_item) {
+    ij_item_ = ij_item;
+    ++num_packets_;
+  }
+
+  RTCPUtility::RTCPPacketExtendedJitterReportItem ij_item_;
+};
+
+class Sdes : public PacketType {
+ public:
+  Sdes() {}
+  virtual ~Sdes() {}
+
+ private:
+  friend class RtcpPacketParser;
+
+  void Set() { ++num_packets_; }
+};
+
+class SdesChunk : public PacketType {
+ public:
+  SdesChunk() {}
+  virtual ~SdesChunk() {}
+
+  uint32_t Ssrc() const { return cname_.SenderSSRC; }
+  std::string Cname() const { return cname_.CName; }
+
+ private:
+  friend class RtcpPacketParser;
+
+  void Set(const RTCPUtility::RTCPPacketSDESCName& cname) {
+    cname_ = cname;
+    ++num_packets_;
+  }
+
+  RTCPUtility::RTCPPacketSDESCName cname_;
+};
+
 class Bye : public PacketType {
  public:
   Bye() {}
@@ -140,6 +200,102 @@
   RTCPUtility::RTCPPacketPSFBRPSI rpsi_;
 };
 
+class App : public PacketType {
+ public:
+  App() {}
+  virtual ~App() {}
+
+  uint8_t SubType() const { return app_.SubType; }
+  uint32_t Name() const { return app_.Name; }
+
+ private:
+  friend class RtcpPacketParser;
+
+  void Set(const RTCPUtility::RTCPPacketAPP& app) {
+    app_ = app;
+    ++num_packets_;
+  }
+
+  RTCPUtility::RTCPPacketAPP app_;
+};
+
+class AppItem : public PacketType {
+ public:
+  AppItem() {}
+  virtual ~AppItem() {}
+
+  uint8_t* Data() { return app_item_.Data; }
+  uint16_t DataLength() const { return app_item_.Size; }
+
+ private:
+  friend class RtcpPacketParser;
+
+  void Set(const RTCPUtility::RTCPPacketAPP& app) {
+    app_item_ = app;
+    ++num_packets_;
+  }
+
+  RTCPUtility::RTCPPacketAPP app_item_;
+};
+
+class Pli : public PacketType {
+ public:
+  Pli() {}
+  virtual ~Pli() {}
+
+  uint32_t Ssrc() const { return pli_.SenderSSRC; }
+  uint32_t MediaSsrc() const { return pli_.MediaSSRC; }
+
+ private:
+  friend class RtcpPacketParser;
+
+  void Set(const RTCPUtility::RTCPPacketPSFBPLI& pli) {
+    pli_ = pli;
+    ++num_packets_;
+  }
+
+  RTCPUtility::RTCPPacketPSFBPLI pli_;
+};
+
+class Sli : public PacketType {
+ public:
+  Sli() {}
+  virtual ~Sli() {}
+
+  uint32_t Ssrc() const { return sli_.SenderSSRC; }
+  uint32_t MediaSsrc() const { return sli_.MediaSSRC; }
+
+ private:
+  friend class RtcpPacketParser;
+
+  void Set(const RTCPUtility::RTCPPacketPSFBSLI& sli) {
+    sli_ = sli;
+    ++num_packets_;
+  }
+
+  RTCPUtility::RTCPPacketPSFBSLI sli_;
+};
+
+class SliItem : public PacketType {
+ public:
+  SliItem() {}
+  virtual ~SliItem() {}
+
+  uint16_t FirstMb() const { return sli_item_.FirstMB; }
+  uint16_t NumberOfMb() const { return sli_item_.NumberOfMB; }
+  uint8_t PictureId() const { return sli_item_.PictureId; }
+
+ private:
+  friend class RtcpPacketParser;
+
+  void Set(const RTCPUtility::RTCPPacketPSFBSLIItem& sli_item) {
+    sli_item_ = sli_item;
+    ++num_packets_;
+  }
+
+  RTCPUtility::RTCPPacketPSFBSLIItem sli_item_;
+};
+
 class Fir : public PacketType {
  public:
   Fir() {}
@@ -232,7 +388,16 @@
   SenderReport* sender_report() { return &sender_report_; }
   ReceiverReport* receiver_report() { return &receiver_report_; }
   ReportBlock* report_block() { return &report_block_; }
+  Sdes* sdes() { return &sdes_; }
+  SdesChunk* sdes_chunk() { return &sdes_chunk_; }
   Bye* bye() { return &bye_; }
+  App* app() { return &app_; }
+  AppItem* app_item() { return &app_item_; }
+  Ij* ij() { return &ij_; }
+  IjItem* ij_item() { return &ij_item_; }
+  Pli* pli() { return &pli_; }
+  Sli* sli() { return &sli_; }
+  SliItem* sli_item() { return &sli_item_; }
   Rpsi* rpsi() { return &rpsi_; }
   Fir* fir() { return &fir_; }
   FirItem* fir_item() { return &fir_item_; }
@@ -247,7 +412,16 @@
   SenderReport sender_report_;
   ReceiverReport receiver_report_;
   ReportBlock report_block_;
+  Sdes sdes_;
+  SdesChunk sdes_chunk_;
   Bye bye_;
+  App app_;
+  AppItem app_item_;
+  Ij ij_;
+  IjItem ij_item_;
+  Pli pli_;
+  Sli sli_;
+  SliItem sli_item_;
   Rpsi rpsi_;
   Fir fir_;
   FirItem fir_item_;