Add RTCP packet types to packet builder:
REMB, TMMBR, TMMBN and
extended reports: RRTR, DLRR, VoIP metric.

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

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

git-svn-id: http://webrtc.googlecode.com/svn/trunk@6537 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 a4cdfd9..f6d3bd3 100644
--- a/webrtc/modules/rtp_rtcp/source/rtcp_packet.cc
+++ b/webrtc/modules/rtp_rtcp/source/rtcp_packet.cc
@@ -13,6 +13,10 @@
 #include "webrtc/modules/rtp_rtcp/source/rtp_utility.h"
 #include "webrtc/system_wrappers/interface/logging.h"
 
+using webrtc::RTCPUtility::kBtDlrr;
+using webrtc::RTCPUtility::kBtReceiverReferenceTime;
+using webrtc::RTCPUtility::kBtVoipMetric;
+
 using webrtc::RTCPUtility::PT_APP;
 using webrtc::RTCPUtility::PT_BYE;
 using webrtc::RTCPUtility::PT_IJ;
@@ -69,6 +73,24 @@
   *offset += 4;
 }
 
+void ComputeMantissaAnd6bitBase2Exponent(uint32_t input_base10,
+                                         uint8_t bits_mantissa,
+                                         uint32_t* mantissa,
+                                         uint8_t* exp) {
+  // input_base10 = mantissa * 2^exp
+  assert(bits_mantissa <= 32);
+  uint32_t mantissa_max = (1 << bits_mantissa) - 1;
+  uint8_t exponent = 0;
+  for (uint32_t i = 0; i < 64; ++i) {
+    if (input_base10 <= (mantissa_max << i)) {
+      exponent = i;
+      break;
+    }
+  }
+  *exp = exponent;
+  *mantissa = (input_base10 >> exponent);
+}
+
 size_t BlockToHeaderLength(size_t length_in_bytes) {
   // Length in 32-bit words minus 1.
   assert(length_in_bytes > 0);
@@ -440,6 +462,264 @@
   AssignUWord8(buffer, pos, fir_item.CommandSequenceNumber);
   AssignUWord24(buffer, pos, 0);
 }
+
+void CreateTmmbrItem(const RTCPPacketRTPFBTMMBRItem& tmmbr_item,
+                     uint8_t* buffer,
+                     size_t* pos) {
+  uint32_t bitrate_bps = tmmbr_item.MaxTotalMediaBitRate * 1000;
+  uint32_t mantissa = 0;
+  uint8_t exp = 0;
+  ComputeMantissaAnd6bitBase2Exponent(bitrate_bps, 17, &mantissa, &exp);
+
+  AssignUWord32(buffer, pos, tmmbr_item.SSRC);
+  AssignUWord8(buffer, pos, (exp << 2) + ((mantissa >> 15) & 0x03));
+  AssignUWord8(buffer, pos, mantissa >> 7);
+  AssignUWord8(buffer, pos, (mantissa << 1) +
+                            ((tmmbr_item.MeasuredOverhead >> 8) & 0x01));
+  AssignUWord8(buffer, pos, tmmbr_item.MeasuredOverhead);
+}
+
+// Temporary Maximum Media Stream Bit Rate Request (TMMBR) (RFC 5104).
+//
+// 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
+//   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+//   |                              SSRC                             |
+//   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+//   | MxTBR Exp |  MxTBR Mantissa                 |Measured Overhead|
+//   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+
+void CreateTmmbr(const RTCPPacketRTPFBTMMBR& tmmbr,
+                 const RTCPPacketRTPFBTMMBRItem& tmmbr_item,
+                 size_t length,
+                 uint8_t* buffer,
+                 size_t* pos) {
+  const uint8_t kFmt = 3;
+  CreateHeader(kFmt, PT_RTPFB, length, buffer, pos);
+  AssignUWord32(buffer, pos, tmmbr.SenderSSRC);
+  AssignUWord32(buffer, pos, kUnusedMediaSourceSsrc0);
+  CreateTmmbrItem(tmmbr_item, buffer, pos);
+}
+
+// Temporary Maximum Media Stream Bit Rate Notification (TMMBN) (RFC 5104).
+//
+// 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
+//   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+//   |                              SSRC                             |
+//   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+//   | MxTBR Exp |  MxTBR Mantissa                 |Measured Overhead|
+//   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+
+void CreateTmmbn(const RTCPPacketRTPFBTMMBN& tmmbn,
+                 const std::vector<RTCPPacketRTPFBTMMBRItem>& tmmbn_items,
+                 size_t length,
+                 uint8_t* buffer,
+                 size_t* pos) {
+  const uint8_t kFmt = 4;
+  CreateHeader(kFmt, PT_RTPFB, length, buffer, pos);
+  AssignUWord32(buffer, pos, tmmbn.SenderSSRC);
+  AssignUWord32(buffer, pos, kUnusedMediaSourceSsrc0);
+  for (uint8_t i = 0; i < tmmbn_items.size(); ++i) {
+    CreateTmmbrItem(tmmbn_items[i], buffer, pos);
+  }
+}
+
+// Receiver Estimated Max Bitrate (REMB) (draft-alvestrand-rmcat-remb).
+//
+//    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| FMT=15  |   PT=206      |             length            |
+//   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+//   |                  SSRC of packet sender                        |
+//   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+//   |                  SSRC of media source                         |
+//   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+//   |  Unique identifier 'R' 'E' 'M' 'B'                            |
+//   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+//   |  Num SSRC     | BR Exp    |  BR Mantissa                      |
+//   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+//   |   SSRC feedback                                               |
+//   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+//   |  ...                                                          |
+
+void CreateRemb(const RTCPPacketPSFBAPP& remb,
+                const RTCPPacketPSFBREMBItem& remb_item,
+                size_t length,
+                uint8_t* buffer,
+                size_t* pos) {
+  uint32_t mantissa = 0;
+  uint8_t exp = 0;
+  ComputeMantissaAnd6bitBase2Exponent(remb_item.BitRate, 18, &mantissa, &exp);
+
+  const uint8_t kFmt = 15;
+  CreateHeader(kFmt, PT_PSFB, length, buffer, pos);
+  AssignUWord32(buffer, pos, remb.SenderSSRC);
+  AssignUWord32(buffer, pos, kUnusedMediaSourceSsrc0);
+  AssignUWord8(buffer, pos, 'R');
+  AssignUWord8(buffer, pos, 'E');
+  AssignUWord8(buffer, pos, 'M');
+  AssignUWord8(buffer, pos, 'B');
+  AssignUWord8(buffer, pos, remb_item.NumberOfSSRCs);
+  AssignUWord8(buffer, pos, (exp << 2) + ((mantissa >> 16) & 0x03));
+  AssignUWord8(buffer, pos, mantissa >> 8);
+  AssignUWord8(buffer, pos, mantissa);
+  for (uint8_t i = 0; i < remb_item.NumberOfSSRCs; ++i) {
+    AssignUWord32(buffer, pos, remb_item.SSRCs[i]);
+  }
+}
+
+// From RFC 3611: RTP Control Protocol Extended Reports (RTCP XR).
+//
+// Format for XR packets:
+//
+//   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|reserved |   PT=XR=207   |             length            |
+//  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+//  |                              SSRC                             |
+//  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+//  :                         report blocks                         :
+//  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+
+void CreateXrHeader(const RTCPPacketXR& header,
+                    size_t length,
+                    uint8_t* buffer,
+                    size_t* pos) {
+  CreateHeader(0U, PT_XR, length, buffer, pos);
+  AssignUWord32(buffer, pos, header.OriginatorSSRC);
+}
+
+void CreateXrBlockHeader(uint8_t block_type,
+                         uint16_t block_length,
+                         uint8_t* buffer,
+                         size_t* pos) {
+  AssignUWord8(buffer, pos, block_type);
+  AssignUWord8(buffer, pos, 0);
+  AssignUWord16(buffer, pos, block_length);
+}
+
+// Receiver Reference Time Report Block (RFC 3611).
+//
+//   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
+//  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+//  |     BT=4      |   reserved    |       block length = 2        |
+//  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+//  |              NTP timestamp, most significant word             |
+//  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+//  |             NTP timestamp, least significant word             |
+//  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+
+void CreateRrtr(const std::vector<RTCPPacketXRReceiverReferenceTimeItem>& rrtrs,
+                uint8_t* buffer,
+                size_t* pos) {
+  const uint16_t kBlockLength = 2;
+  for (std::vector<RTCPPacketXRReceiverReferenceTimeItem>::const_iterator it =
+       rrtrs.begin(); it != rrtrs.end(); ++it) {
+    CreateXrBlockHeader(kBtReceiverReferenceTime, kBlockLength, buffer, pos);
+    AssignUWord32(buffer, pos, (*it).NTPMostSignificant);
+    AssignUWord32(buffer, pos, (*it).NTPLeastSignificant);
+  }
+}
+
+// DLRR Report Block (RFC 3611).
+//
+//   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
+//  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+//  |     BT=5      |   reserved    |         block length          |
+//  +=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+
+//  |                 SSRC_1 (SSRC of first receiver)               | sub-
+//  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ block
+//  |                         last RR (LRR)                         |   1
+//  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+//  |                   delay since last RR (DLRR)                  |
+//  +=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+
+//  |                 SSRC_2 (SSRC of second receiver)              | sub-
+//  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ block
+//  :                               ...                             :   2
+
+void CreateDlrr(const std::vector<Xr::DlrrBlock>& dlrrs,
+                uint8_t* buffer,
+                size_t* pos) {
+  for (std::vector<Xr::DlrrBlock>::const_iterator it = dlrrs.begin();
+       it != dlrrs.end(); ++it) {
+    if ((*it).empty()) {
+      continue;
+    }
+    uint16_t block_length = 3 * (*it).size();
+    CreateXrBlockHeader(kBtDlrr, block_length, buffer, pos);
+    for (Xr::DlrrBlock::const_iterator it_block = (*it).begin();
+         it_block != (*it).end(); ++it_block) {
+      AssignUWord32(buffer, pos, (*it_block).SSRC);
+      AssignUWord32(buffer, pos, (*it_block).LastRR);
+      AssignUWord32(buffer, pos, (*it_block).DelayLastRR);
+    }
+  }
+}
+
+// VoIP Metrics Report Block (RFC 3611).
+//
+//   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
+//  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+//  |     BT=7      |   reserved    |       block length = 8        |
+//  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+//  |                        SSRC of source                         |
+//  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+//  |   loss rate   | discard rate  | burst density |  gap density  |
+//  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+//  |       burst duration          |         gap duration          |
+//  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+//  |     round trip delay          |       end system delay        |
+//  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+//  | signal level  |  noise level  |     RERL      |     Gmin      |
+//  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+//  |   R factor    | ext. R factor |    MOS-LQ     |    MOS-CQ     |
+//  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+//  |   RX config   |   reserved    |          JB nominal           |
+//  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+//  |          JB maximum           |          JB abs max           |
+//  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+
+void CreateVoipMetric(const std::vector<RTCPPacketXRVOIPMetricItem>& metrics,
+                      uint8_t* buffer,
+                      size_t* pos) {
+  const uint16_t kBlockLength = 8;
+  for (std::vector<RTCPPacketXRVOIPMetricItem>::const_iterator it =
+       metrics.begin(); it != metrics.end(); ++it) {
+    CreateXrBlockHeader(kBtVoipMetric, kBlockLength, buffer, pos);
+    AssignUWord32(buffer, pos, (*it).SSRC);
+    AssignUWord8(buffer, pos, (*it).lossRate);
+    AssignUWord8(buffer, pos, (*it).discardRate);
+    AssignUWord8(buffer, pos, (*it).burstDensity);
+    AssignUWord8(buffer, pos, (*it).gapDensity);
+    AssignUWord16(buffer, pos, (*it).burstDuration);
+    AssignUWord16(buffer, pos, (*it).gapDuration);
+    AssignUWord16(buffer, pos, (*it).roundTripDelay);
+    AssignUWord16(buffer, pos, (*it).endSystemDelay);
+    AssignUWord8(buffer, pos, (*it).signalLevel);
+    AssignUWord8(buffer, pos, (*it).noiseLevel);
+    AssignUWord8(buffer, pos, (*it).RERL);
+    AssignUWord8(buffer, pos, (*it).Gmin);
+    AssignUWord8(buffer, pos, (*it).Rfactor);
+    AssignUWord8(buffer, pos, (*it).extRfactor);
+    AssignUWord8(buffer, pos, (*it).MOSLQ);
+    AssignUWord8(buffer, pos, (*it).MOSCQ);
+    AssignUWord8(buffer, pos, (*it).RXconfig);
+    AssignUWord8(buffer, pos, 0);
+    AssignUWord16(buffer, pos, (*it).JBnominal);
+    AssignUWord16(buffer, pos, (*it).JBmax);
+    AssignUWord16(buffer, pos, (*it).JBabsMax);
+  }
+}
 }  // namespace
 
 void RtcpPacket::Append(RtcpPacket* packet) {
@@ -691,5 +971,120 @@
   CreateFir(fir_, fir_item_, BlockToHeaderLength(BlockLength()), packet,
             length);
 }
+
+void Remb::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;
+  }
+  CreateRemb(remb_, remb_item_, BlockToHeaderLength(BlockLength()), packet,
+             length);
+}
+
+void Remb::AppliesTo(uint32_t ssrc) {
+  if (remb_item_.NumberOfSSRCs >= kMaxNumberOfSsrcs) {
+    LOG(LS_WARNING) << "Max number of REMB feedback SSRCs reached.";
+    return;
+  }
+  remb_item_.SSRCs[remb_item_.NumberOfSSRCs++] = ssrc;
+}
+
+void Tmmbr::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;
+  }
+  CreateTmmbr(tmmbr_, tmmbr_item_, BlockToHeaderLength(BlockLength()), packet,
+              length);
+}
+
+void Tmmbn::WithTmmbr(uint32_t ssrc, uint32_t bitrate_kbps, uint16_t overhead) {
+  assert(overhead <= 0x1ff);
+  if (tmmbn_items_.size() >= kMaxNumberOfTmmbrs) {
+    LOG(LS_WARNING) << "Max TMMBN size reached.";
+    return;
+  }
+  RTCPPacketRTPFBTMMBRItem tmmbn_item;
+  tmmbn_item.SSRC = ssrc;
+  tmmbn_item.MaxTotalMediaBitRate = bitrate_kbps;
+  tmmbn_item.MeasuredOverhead = overhead;
+  tmmbn_items_.push_back(tmmbn_item);
+}
+
+void Tmmbn::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;
+  }
+  CreateTmmbn(tmmbn_, tmmbn_items_, BlockToHeaderLength(BlockLength()), packet,
+              length);
+}
+
+void Xr::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;
+  }
+  CreateXrHeader(xr_header_, BlockToHeaderLength(BlockLength()), packet,
+                 length);
+  CreateRrtr(rrtr_blocks_, packet, length);
+  CreateDlrr(dlrr_blocks_, packet, length);
+  CreateVoipMetric(voip_metric_blocks_, packet, length);
+}
+
+void Xr::WithRrtr(Rrtr* rrtr) {
+  assert(rrtr);
+  if (rrtr_blocks_.size() >= kMaxNumberOfRrtrBlocks) {
+    LOG(LS_WARNING) << "Max RRTR blocks reached.";
+    return;
+  }
+  rrtr_blocks_.push_back(rrtr->rrtr_block_);
+}
+
+void Xr::WithDlrr(Dlrr* dlrr) {
+  assert(dlrr);
+  if (dlrr_blocks_.size() >= kMaxNumberOfDlrrBlocks) {
+    LOG(LS_WARNING) << "Max DLRR blocks reached.";
+    return;
+  }
+  dlrr_blocks_.push_back(dlrr->dlrr_block_);
+}
+
+void Xr::WithVoipMetric(VoipMetric* voip_metric) {
+  assert(voip_metric);
+  if (voip_metric_blocks_.size() >= kMaxNumberOfVoipMetricBlocks) {
+    LOG(LS_WARNING) << "Max Voip Metric blocks reached.";
+    return;
+  }
+  voip_metric_blocks_.push_back(voip_metric->metric_);
+}
+
+size_t Xr::DlrrLength() const {
+  const size_t kBlockHeaderLen = 4;
+  const size_t kSubBlockLen = 12;
+  size_t length = 0;
+  for (std::vector<DlrrBlock>::const_iterator it = dlrr_blocks_.begin();
+       it != dlrr_blocks_.end(); ++it) {
+    if (!(*it).empty()) {
+      length += kBlockHeaderLen + kSubBlockLen * (*it).size();
+    }
+  }
+  return length;
+}
+
+void Dlrr::WithDlrrItem(uint32_t ssrc,
+                        uint32_t last_rr,
+                        uint32_t delay_last_rr) {
+  if (dlrr_block_.size() >= kMaxNumberOfDlrrItems) {
+    LOG(LS_WARNING) << "Max DLRR items reached.";
+    return;
+  }
+  RTCPPacketXRDLRRReportBlockItem dlrr;
+  dlrr.SSRC = ssrc;
+  dlrr.LastRR = last_rr;
+  dlrr.DelayLastRR = delay_last_rr;
+  dlrr_block_.push_back(dlrr);
+}
+
 }  // 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 f60e848..0ea98a2 100644
--- a/webrtc/modules/rtp_rtcp/source/rtcp_packet.h
+++ b/webrtc/modules/rtp_rtcp/source/rtcp_packet.h
@@ -26,7 +26,10 @@
 enum { kCommonFbFmtLength = 12 };
 enum { kReportBlockLength = 24 };
 
+class Dlrr;
 class RawPacket;
+class Rrtr;
+class VoipMetric;
 
 // Class for building RTCP packets.
 //
@@ -82,12 +85,16 @@
 
 class Empty : public RtcpPacket {
  public:
-  Empty() {}
+  Empty() : RtcpPacket() {}
 
   virtual ~Empty() {}
 
  protected:
-  virtual void Create(uint8_t* packet, size_t* length, size_t max_length) const;
+  virtual void Create(
+      uint8_t* packet, size_t* length, size_t max_length) const OVERRIDE;
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(Empty);
 };
 
 // From RFC 3550, RTP: A Transport Protocol for Real-Time Applications.
@@ -212,6 +219,8 @@
 
   RTCPUtility::RTCPPacketSR sr_;
   std::vector<RTCPUtility::RTCPPacketReportBlockItem> report_blocks_;
+
+  DISALLOW_COPY_AND_ASSIGN(SenderReport);
 };
 
 //
@@ -254,6 +263,8 @@
 
   RTCPUtility::RTCPPacketRR rr_;
   std::vector<RTCPUtility::RTCPPacketReportBlockItem> report_blocks_;
+
+  DISALLOW_COPY_AND_ASSIGN(ReceiverReport);
 };
 
 // Transmission Time Offsets in RTP Streams (RFC 5450).
@@ -394,6 +405,8 @@
 
   RTCPUtility::RTCPPacketBYE bye_;
   std::vector<uint32_t> csrcs_;
+
+  DISALLOW_COPY_AND_ASSIGN(Bye);
 };
 
 // Application-Defined packet (APP) (RFC 3550).
@@ -660,8 +673,7 @@
 
 class Fir : public RtcpPacket {
  public:
-  Fir()
-      : RtcpPacket() {
+  Fir() : RtcpPacket() {
     memset(&fir_, 0, sizeof(fir_));
     memset(&fir_item_, 0, sizeof(fir_item_));
   }
@@ -692,6 +704,354 @@
   RTCPUtility::RTCPPacketPSFBFIRItem fir_item_;
 };
 
+// Temporary Maximum Media Stream Bit Rate Request (TMMBR) (RFC 5104).
+//
+// 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
+//   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+//   |                              SSRC                             |
+//   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+//   | MxTBR Exp |  MxTBR Mantissa                 |Measured Overhead|
+//   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+
+class Tmmbr : public RtcpPacket {
+ public:
+  Tmmbr() : RtcpPacket() {
+    memset(&tmmbr_, 0, sizeof(tmmbr_));
+    memset(&tmmbr_item_, 0, sizeof(tmmbr_item_));
+  }
+
+  virtual ~Tmmbr() {}
+
+  void From(uint32_t ssrc) {
+    tmmbr_.SenderSSRC = ssrc;
+  }
+  void To(uint32_t ssrc) {
+    tmmbr_item_.SSRC = ssrc;
+  }
+  void WithBitrateKbps(uint32_t bitrate_kbps) {
+    tmmbr_item_.MaxTotalMediaBitRate = bitrate_kbps;
+  }
+  void WithOverhead(uint16_t overhead) {
+    assert(overhead <= 0x1ff);
+    tmmbr_item_.MeasuredOverhead = overhead;
+  }
+
+ protected:
+  virtual void Create(
+      uint8_t* packet, size_t* length, size_t max_length) const OVERRIDE;
+
+ private:
+  size_t BlockLength() const {
+    const size_t kFciLen = 8;
+    return kCommonFbFmtLength + kFciLen;
+  }
+
+  RTCPUtility::RTCPPacketRTPFBTMMBR tmmbr_;
+  RTCPUtility::RTCPPacketRTPFBTMMBRItem tmmbr_item_;
+
+  DISALLOW_COPY_AND_ASSIGN(Tmmbr);
+};
+
+// Temporary Maximum Media Stream Bit Rate Notification (TMMBN) (RFC 5104).
+//
+// 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
+//   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+//   |                              SSRC                             |
+//   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+//   | MxTBR Exp |  MxTBR Mantissa                 |Measured Overhead|
+//   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+
+class Tmmbn : public RtcpPacket {
+ public:
+  Tmmbn() : RtcpPacket() {
+    memset(&tmmbn_, 0, sizeof(tmmbn_));
+  }
+
+  virtual ~Tmmbn() {}
+
+  void From(uint32_t ssrc) {
+    tmmbn_.SenderSSRC = ssrc;
+  }
+  void WithTmmbr(uint32_t ssrc, uint32_t bitrate_kbps, uint16_t overhead);
+
+ protected:
+  virtual void Create(
+      uint8_t* packet, size_t* length, size_t max_length) const OVERRIDE;
+
+ private:
+  enum { kMaxNumberOfTmmbrs = 50 };
+
+  size_t BlockLength() const {
+    const size_t kFciLen = 8;
+    return kCommonFbFmtLength + kFciLen * tmmbn_items_.size();
+  }
+
+  RTCPUtility::RTCPPacketRTPFBTMMBN tmmbn_;
+  std::vector<RTCPUtility::RTCPPacketRTPFBTMMBRItem> tmmbn_items_;
+
+  DISALLOW_COPY_AND_ASSIGN(Tmmbn);
+};
+
+// Receiver Estimated Max Bitrate (REMB) (draft-alvestrand-rmcat-remb).
+//
+//    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| FMT=15  |   PT=206      |             length            |
+//   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+//   |                  SSRC of packet sender                        |
+//   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+//   |                  SSRC of media source                         |
+//   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+//   |  Unique identifier 'R' 'E' 'M' 'B'                            |
+//   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+//   |  Num SSRC     | BR Exp    |  BR Mantissa                      |
+//   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+//   |   SSRC feedback                                               |
+//   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+//   |  ...
+
+class Remb : public RtcpPacket {
+ public:
+  Remb() : RtcpPacket() {
+    memset(&remb_, 0, sizeof(remb_));
+    memset(&remb_item_, 0, sizeof(remb_item_));
+  }
+
+  virtual ~Remb() {}
+
+  void From(uint32_t ssrc) {
+    remb_.SenderSSRC = ssrc;
+  }
+  void AppliesTo(uint32_t ssrc);
+
+  void WithBitrateBps(uint32_t bitrate_bps) {
+    remb_item_.BitRate = bitrate_bps;
+  }
+
+ protected:
+  virtual void Create(
+      uint8_t* packet, size_t* length, size_t max_length) const OVERRIDE;
+
+ private:
+  enum { kMaxNumberOfSsrcs = 0xff };
+
+  size_t BlockLength() const {
+    return (remb_item_.NumberOfSSRCs + 5) * 4;
+  }
+
+  RTCPUtility::RTCPPacketPSFBAPP remb_;
+  RTCPUtility::RTCPPacketPSFBREMBItem remb_item_;
+
+  DISALLOW_COPY_AND_ASSIGN(Remb);
+};
+
+// From RFC 3611: RTP Control Protocol Extended Reports (RTCP XR).
+//
+// Format for XR packets:
+//
+//   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|reserved |   PT=XR=207   |             length            |
+//  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+//  |                              SSRC                             |
+//  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+//  :                         report blocks                         :
+//  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+
+class Xr : public RtcpPacket {
+ public:
+  typedef std::vector<RTCPUtility::RTCPPacketXRDLRRReportBlockItem> DlrrBlock;
+  Xr() : RtcpPacket() {
+    memset(&xr_header_, 0, sizeof(xr_header_));
+  }
+
+  virtual ~Xr() {}
+
+  void From(uint32_t ssrc) {
+    xr_header_.OriginatorSSRC = ssrc;
+  }
+  void WithRrtr(Rrtr* rrtr);
+  void WithDlrr(Dlrr* dlrr);
+  void WithVoipMetric(VoipMetric* voip_metric);
+
+ protected:
+  virtual void Create(
+      uint8_t* packet, size_t* length, size_t max_length) const OVERRIDE;
+
+ private:
+  enum { kMaxNumberOfRrtrBlocks = 50 };
+  enum { kMaxNumberOfDlrrBlocks = 50 };
+  enum { kMaxNumberOfVoipMetricBlocks = 50 };
+
+  size_t BlockLength() const {
+    const size_t kXrHeaderLength = 8;
+    return kXrHeaderLength + RrtrLength() + DlrrLength() + VoipMetricLength();
+  }
+
+  size_t RrtrLength() const {
+    const size_t kRrtrBlockLength = 12;
+    return kRrtrBlockLength * rrtr_blocks_.size();
+  }
+
+  size_t DlrrLength() const;
+
+  size_t VoipMetricLength() const {
+    const size_t kVoipMetricBlockLength = 36;
+    return kVoipMetricBlockLength * voip_metric_blocks_.size();
+  }
+
+  RTCPUtility::RTCPPacketXR xr_header_;
+  std::vector<RTCPUtility::RTCPPacketXRReceiverReferenceTimeItem> rrtr_blocks_;
+  std::vector<DlrrBlock> dlrr_blocks_;
+  std::vector<RTCPUtility::RTCPPacketXRVOIPMetricItem> voip_metric_blocks_;
+
+  DISALLOW_COPY_AND_ASSIGN(Xr);
+};
+
+// Receiver Reference Time Report Block (RFC 3611).
+//
+//   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
+//  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+//  |     BT=4      |   reserved    |       block length = 2        |
+//  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+//  |              NTP timestamp, most significant word             |
+//  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+//  |             NTP timestamp, least significant word             |
+//  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+
+class Rrtr {
+ public:
+  Rrtr() {
+    memset(&rrtr_block_, 0, sizeof(rrtr_block_));
+  }
+  ~Rrtr() {}
+
+  void WithNtpSec(uint32_t sec) {
+    rrtr_block_.NTPMostSignificant = sec;
+  }
+  void WithNtpFrac(uint32_t frac) {
+    rrtr_block_.NTPLeastSignificant = frac;
+  }
+
+ private:
+  friend class Xr;
+  RTCPUtility::RTCPPacketXRReceiverReferenceTimeItem rrtr_block_;
+
+  DISALLOW_COPY_AND_ASSIGN(Rrtr);
+};
+
+// DLRR Report Block (RFC 3611).
+//
+//   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
+//  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+//  |     BT=5      |   reserved    |         block length          |
+//  +=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+
+//  |                 SSRC_1 (SSRC of first receiver)               | sub-
+//  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ block
+//  |                         last RR (LRR)                         |   1
+//  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+//  |                   delay since last RR (DLRR)                  |
+//  +=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+
+//  |                 SSRC_2 (SSRC of second receiver)              | sub-
+//  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ block
+//  :                               ...                             :   2
+
+class Dlrr {
+ public:
+  Dlrr() {}
+  ~Dlrr() {}
+
+  void WithDlrrItem(uint32_t ssrc, uint32_t last_rr, uint32_t delay_last_rr);
+
+ private:
+  friend class Xr;
+  enum { kMaxNumberOfDlrrItems = 100 };
+
+  std::vector<RTCPUtility::RTCPPacketXRDLRRReportBlockItem> dlrr_block_;
+
+  DISALLOW_COPY_AND_ASSIGN(Dlrr);
+};
+
+// VoIP Metrics Report Block (RFC 3611).
+//
+//   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
+//  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+//  |     BT=7      |   reserved    |       block length = 8        |
+//  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+//  |                        SSRC of source                         |
+//  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+//  |   loss rate   | discard rate  | burst density |  gap density  |
+//  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+//  |       burst duration          |         gap duration          |
+//  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+//  |     round trip delay          |       end system delay        |
+//  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+//  | signal level  |  noise level  |     RERL      |     Gmin      |
+//  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+//  |   R factor    | ext. R factor |    MOS-LQ     |    MOS-CQ     |
+//  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+//  |   RX config   |   reserved    |          JB nominal           |
+//  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+//  |          JB maximum           |          JB abs max           |
+//  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+
+class VoipMetric {
+ public:
+  VoipMetric() {
+    memset(&metric_, 0, sizeof(metric_));
+  }
+  ~VoipMetric() {}
+
+  void To(uint32_t ssrc) { metric_.SSRC = ssrc; }
+  void LossRate(uint8_t loss_rate) { metric_.lossRate = loss_rate; }
+  void DiscardRate(uint8_t discard_rate) { metric_.discardRate = discard_rate; }
+  void BurstDensity(uint8_t burst_density) {
+    metric_.burstDensity = burst_density;
+  }
+  void GapDensity(uint8_t gap_density) { metric_.gapDensity = gap_density; }
+  void BurstDuration(uint16_t burst_duration) {
+    metric_.burstDuration = burst_duration;
+  }
+  void GapDuration(uint16_t gap_duration) {
+    metric_.gapDuration = gap_duration;
+  }
+  void RoundTripDelay(uint16_t round_trip_delay) {
+    metric_.roundTripDelay = round_trip_delay;
+  }
+  void EndSystemDelay(uint16_t end_system_delay) {
+    metric_.endSystemDelay = end_system_delay;
+  }
+  void SignalLevel(uint8_t signal_level) { metric_.signalLevel = signal_level; }
+  void NoiseLevel(uint8_t noise_level) { metric_.noiseLevel = noise_level; }
+  void Rerl(uint8_t rerl) { metric_.RERL = rerl; }
+  void Gmin(uint8_t gmin) { metric_.Gmin = gmin; }
+  void Rfactor(uint8_t rfactor) { metric_.Rfactor = rfactor; }
+  void ExtRfactor(uint8_t extrfactor) { metric_.extRfactor = extrfactor; }
+  void MosLq(uint8_t moslq) { metric_.MOSLQ = moslq; }
+  void MosCq(uint8_t moscq) { metric_.MOSCQ = moscq; }
+  void RxConfig(uint8_t rxconfig) { metric_.RXconfig = rxconfig; }
+  void JbNominal(uint16_t jbnominal) { metric_.JBnominal = jbnominal; }
+  void JbMax(uint16_t jbmax) { metric_.JBmax = jbmax; }
+  void JbAbsMax(uint16_t jbabsmax) { metric_.JBabsMax = jbabsmax; }
+
+ private:
+  friend class Xr;
+  RTCPUtility::RTCPPacketXRVOIPMetricItem metric_;
+
+  DISALLOW_COPY_AND_ASSIGN(VoipMetric);
+};
+
 // Class holding a RTCP packet.
 //
 // Takes a built rtcp packet.
diff --git a/webrtc/modules/rtp_rtcp/source/rtcp_packet_unittest.cc b/webrtc/modules/rtp_rtcp/source/rtcp_packet_unittest.cc
index aa25c2e..095022e 100644
--- a/webrtc/modules/rtp_rtcp/source/rtcp_packet_unittest.cc
+++ b/webrtc/modules/rtp_rtcp/source/rtcp_packet_unittest.cc
@@ -17,6 +17,7 @@
 
 using webrtc::rtcp::App;
 using webrtc::rtcp::Bye;
+using webrtc::rtcp::Dlrr;
 using webrtc::rtcp::Empty;
 using webrtc::rtcp::Fir;
 using webrtc::rtcp::Ij;
@@ -27,8 +28,15 @@
 using webrtc::rtcp::Sli;
 using webrtc::rtcp::RawPacket;
 using webrtc::rtcp::ReceiverReport;
+using webrtc::rtcp::Remb;
 using webrtc::rtcp::ReportBlock;
 using webrtc::rtcp::Rpsi;
+using webrtc::rtcp::Rrtr;
+using webrtc::rtcp::SenderReport;
+using webrtc::rtcp::Tmmbn;
+using webrtc::rtcp::Tmmbr;
+using webrtc::rtcp::VoipMetric;
+using webrtc::rtcp::Xr;
 using webrtc::test::RtcpPacketParser;
 
 namespace webrtc {
@@ -589,4 +597,307 @@
   EXPECT_EQ(0, parser.report_block()->num_packets());
   EXPECT_EQ(1, parser.fir()->num_packets());
 }
+
+TEST(RtcpPacketTest, Remb) {
+  Remb remb;
+  remb.From(kSenderSsrc);
+  remb.AppliesTo(kRemoteSsrc);
+  remb.AppliesTo(kRemoteSsrc + 1);
+  remb.AppliesTo(kRemoteSsrc + 2);
+  remb.WithBitrateBps(261011);
+
+  RawPacket packet = remb.Build();
+  RtcpPacketParser parser;
+  parser.Parse(packet.buffer(), packet.buffer_length());
+  EXPECT_EQ(1, parser.psfb_app()->num_packets());
+  EXPECT_EQ(kSenderSsrc, parser.psfb_app()->Ssrc());
+  EXPECT_EQ(1, parser.remb_item()->num_packets());
+  EXPECT_EQ(261011, parser.remb_item()->last_bitrate_bps());
+  std::vector<uint32_t> ssrcs = parser.remb_item()->last_ssrc_list();
+  EXPECT_EQ(kRemoteSsrc, ssrcs[0]);
+  EXPECT_EQ(kRemoteSsrc + 1, ssrcs[1]);
+  EXPECT_EQ(kRemoteSsrc + 2, ssrcs[2]);
+}
+
+TEST(RtcpPacketTest, Tmmbr) {
+  Tmmbr tmmbr;
+  tmmbr.From(kSenderSsrc);
+  tmmbr.To(kRemoteSsrc);
+  tmmbr.WithBitrateKbps(312);
+  tmmbr.WithOverhead(60);
+
+  RawPacket packet = tmmbr.Build();
+  RtcpPacketParser parser;
+  parser.Parse(packet.buffer(), packet.buffer_length());
+  EXPECT_EQ(1, parser.tmmbr()->num_packets());
+  EXPECT_EQ(kSenderSsrc, parser.tmmbr()->Ssrc());
+  EXPECT_EQ(1, parser.tmmbr_item()->num_packets());
+  EXPECT_EQ(312U, parser.tmmbr_item()->BitrateKbps());
+  EXPECT_EQ(60U, parser.tmmbr_item()->Overhead());
+}
+
+TEST(RtcpPacketTest, TmmbnWithNoItem) {
+  Tmmbn tmmbn;
+  tmmbn.From(kSenderSsrc);
+
+  RawPacket packet = tmmbn.Build();
+  RtcpPacketParser parser;
+  parser.Parse(packet.buffer(), packet.buffer_length());
+  EXPECT_EQ(1, parser.tmmbn()->num_packets());
+  EXPECT_EQ(kSenderSsrc, parser.tmmbn()->Ssrc());
+  EXPECT_EQ(0, parser.tmmbn_items()->num_packets());
+}
+
+TEST(RtcpPacketTest, TmmbnWithOneItem) {
+  Tmmbn tmmbn;
+  tmmbn.From(kSenderSsrc);
+  tmmbn.WithTmmbr(kRemoteSsrc, 312, 60);
+
+  RawPacket packet = tmmbn.Build();
+  RtcpPacketParser parser;
+  parser.Parse(packet.buffer(), packet.buffer_length());
+  EXPECT_EQ(1, parser.tmmbn()->num_packets());
+  EXPECT_EQ(kSenderSsrc, parser.tmmbn()->Ssrc());
+  EXPECT_EQ(1, parser.tmmbn_items()->num_packets());
+  EXPECT_EQ(kRemoteSsrc, parser.tmmbn_items()->Ssrc(0));
+  EXPECT_EQ(312U, parser.tmmbn_items()->BitrateKbps(0));
+  EXPECT_EQ(60U, parser.tmmbn_items()->Overhead(0));
+}
+
+TEST(RtcpPacketTest, TmmbnWithTwoItems) {
+  Tmmbn tmmbn;
+  tmmbn.From(kSenderSsrc);
+  tmmbn.WithTmmbr(kRemoteSsrc, 312, 60);
+  tmmbn.WithTmmbr(kRemoteSsrc + 1, 1288, 40);
+
+  RawPacket packet = tmmbn.Build();
+  RtcpPacketParser parser;
+  parser.Parse(packet.buffer(), packet.buffer_length());
+  EXPECT_EQ(1, parser.tmmbn()->num_packets());
+  EXPECT_EQ(kSenderSsrc, parser.tmmbn()->Ssrc());
+  EXPECT_EQ(2, parser.tmmbn_items()->num_packets());
+  EXPECT_EQ(kRemoteSsrc, parser.tmmbn_items()->Ssrc(0));
+  EXPECT_EQ(312U, parser.tmmbn_items()->BitrateKbps(0));
+  EXPECT_EQ(60U, parser.tmmbn_items()->Overhead(0));
+  EXPECT_EQ(kRemoteSsrc + 1, parser.tmmbn_items()->Ssrc(1));
+  EXPECT_EQ(1288U, parser.tmmbn_items()->BitrateKbps(1));
+  EXPECT_EQ(40U, parser.tmmbn_items()->Overhead(1));
+}
+
+TEST(RtcpPacketTest, XrWithNoReportBlocks) {
+  Xr xr;
+  xr.From(kSenderSsrc);
+
+  RawPacket packet = xr.Build();
+  RtcpPacketParser parser;
+  parser.Parse(packet.buffer(), packet.buffer_length());
+  EXPECT_EQ(1, parser.xr_header()->num_packets());
+  EXPECT_EQ(kSenderSsrc, parser.xr_header()->Ssrc());
+}
+
+TEST(RtcpPacketTest, XrWithRrtr) {
+  Rrtr rrtr;
+  rrtr.WithNtpSec(0x11111111);
+  rrtr.WithNtpFrac(0x22222222);
+  Xr xr;
+  xr.From(kSenderSsrc);
+  xr.WithRrtr(&rrtr);
+
+  RawPacket packet = xr.Build();
+  RtcpPacketParser parser;
+  parser.Parse(packet.buffer(), packet.buffer_length());
+  EXPECT_EQ(1, parser.xr_header()->num_packets());
+  EXPECT_EQ(kSenderSsrc, parser.xr_header()->Ssrc());
+  EXPECT_EQ(1, parser.rrtr()->num_packets());
+  EXPECT_EQ(0x11111111U, parser.rrtr()->NtpSec());
+  EXPECT_EQ(0x22222222U, parser.rrtr()->NtpFrac());
+}
+
+TEST(RtcpPacketTest, XrWithTwoRrtrBlocks) {
+  Rrtr rrtr1;
+  rrtr1.WithNtpSec(0x11111111);
+  rrtr1.WithNtpFrac(0x22222222);
+  Rrtr rrtr2;
+  rrtr2.WithNtpSec(0x33333333);
+  rrtr2.WithNtpFrac(0x44444444);
+  Xr xr;
+  xr.From(kSenderSsrc);
+  xr.WithRrtr(&rrtr1);
+  xr.WithRrtr(&rrtr2);
+
+  RawPacket packet = xr.Build();
+  RtcpPacketParser parser;
+  parser.Parse(packet.buffer(), packet.buffer_length());
+  EXPECT_EQ(1, parser.xr_header()->num_packets());
+  EXPECT_EQ(kSenderSsrc, parser.xr_header()->Ssrc());
+  EXPECT_EQ(2, parser.rrtr()->num_packets());
+  EXPECT_EQ(0x33333333U, parser.rrtr()->NtpSec());
+  EXPECT_EQ(0x44444444U, parser.rrtr()->NtpFrac());
+}
+
+TEST(RtcpPacketTest, XrWithDlrrWithOneSubBlock) {
+  Dlrr dlrr;
+  dlrr.WithDlrrItem(0x11111111, 0x22222222, 0x33333333);
+  Xr xr;
+  xr.From(kSenderSsrc);
+  xr.WithDlrr(&dlrr);
+
+  RawPacket packet = xr.Build();
+  RtcpPacketParser parser;
+  parser.Parse(packet.buffer(), packet.buffer_length());
+  EXPECT_EQ(1, parser.xr_header()->num_packets());
+  EXPECT_EQ(kSenderSsrc, parser.xr_header()->Ssrc());
+  EXPECT_EQ(1, parser.dlrr()->num_packets());
+  EXPECT_EQ(1, parser.dlrr_items()->num_packets());
+  EXPECT_EQ(0x11111111U, parser.dlrr_items()->Ssrc(0));
+  EXPECT_EQ(0x22222222U, parser.dlrr_items()->LastRr(0));
+  EXPECT_EQ(0x33333333U, parser.dlrr_items()->DelayLastRr(0));
+}
+
+TEST(RtcpPacketTest, XrWithDlrrWithTwoSubBlocks) {
+  Dlrr dlrr;
+  dlrr.WithDlrrItem(0x11111111, 0x22222222, 0x33333333);
+  dlrr.WithDlrrItem(0x44444444, 0x55555555, 0x66666666);
+  Xr xr;
+  xr.From(kSenderSsrc);
+  xr.WithDlrr(&dlrr);
+
+  RawPacket packet = xr.Build();
+  RtcpPacketParser parser;
+  parser.Parse(packet.buffer(), packet.buffer_length());
+  EXPECT_EQ(1, parser.xr_header()->num_packets());
+  EXPECT_EQ(kSenderSsrc, parser.xr_header()->Ssrc());
+  EXPECT_EQ(1, parser.dlrr()->num_packets());
+  EXPECT_EQ(2, parser.dlrr_items()->num_packets());
+  EXPECT_EQ(0x11111111U, parser.dlrr_items()->Ssrc(0));
+  EXPECT_EQ(0x22222222U, parser.dlrr_items()->LastRr(0));
+  EXPECT_EQ(0x33333333U, parser.dlrr_items()->DelayLastRr(0));
+  EXPECT_EQ(0x44444444U, parser.dlrr_items()->Ssrc(1));
+  EXPECT_EQ(0x55555555U, parser.dlrr_items()->LastRr(1));
+  EXPECT_EQ(0x66666666U, parser.dlrr_items()->DelayLastRr(1));
+}
+
+TEST(RtcpPacketTest, XrWithTwoDlrrBlocks) {
+  Dlrr dlrr1;
+  dlrr1.WithDlrrItem(0x11111111, 0x22222222, 0x33333333);
+  Dlrr dlrr2;
+  dlrr2.WithDlrrItem(0x44444444, 0x55555555, 0x66666666);
+  Xr xr;
+  xr.From(kSenderSsrc);
+  xr.WithDlrr(&dlrr1);
+  xr.WithDlrr(&dlrr2);
+
+  RawPacket packet = xr.Build();
+  RtcpPacketParser parser;
+  parser.Parse(packet.buffer(), packet.buffer_length());
+  EXPECT_EQ(1, parser.xr_header()->num_packets());
+  EXPECT_EQ(kSenderSsrc, parser.xr_header()->Ssrc());
+  EXPECT_EQ(2, parser.dlrr()->num_packets());
+  EXPECT_EQ(2, parser.dlrr_items()->num_packets());
+  EXPECT_EQ(0x11111111U, parser.dlrr_items()->Ssrc(0));
+  EXPECT_EQ(0x22222222U, parser.dlrr_items()->LastRr(0));
+  EXPECT_EQ(0x33333333U, parser.dlrr_items()->DelayLastRr(0));
+  EXPECT_EQ(0x44444444U, parser.dlrr_items()->Ssrc(1));
+  EXPECT_EQ(0x55555555U, parser.dlrr_items()->LastRr(1));
+  EXPECT_EQ(0x66666666U, parser.dlrr_items()->DelayLastRr(1));
+}
+
+TEST(RtcpPacketTest, XrWithVoipMetric) {
+  VoipMetric metric;
+  metric.To(kRemoteSsrc);
+  metric.LossRate(1);
+  metric.DiscardRate(2);
+  metric.BurstDensity(3);
+  metric.GapDensity(4);
+  metric.BurstDuration(0x1111);
+  metric.GapDuration(0x2222);
+  metric.RoundTripDelay(0x3333);
+  metric.EndSystemDelay(0x4444);
+  metric.SignalLevel(5);
+  metric.NoiseLevel(6);
+  metric.Rerl(7);
+  metric.Gmin(8);
+  metric.Rfactor(9);
+  metric.ExtRfactor(10);
+  metric.MosLq(11);
+  metric.MosCq(12);
+  metric.RxConfig(13);
+  metric.JbNominal(0x5555);
+  metric.JbMax(0x6666);
+  metric.JbAbsMax(0x7777);
+
+  Xr xr;
+  xr.From(kSenderSsrc);
+  xr.WithVoipMetric(&metric);
+
+  RawPacket packet = xr.Build();
+  RtcpPacketParser parser;
+  parser.Parse(packet.buffer(), packet.buffer_length());
+  EXPECT_EQ(1, parser.xr_header()->num_packets());
+  EXPECT_EQ(kSenderSsrc, parser.xr_header()->Ssrc());
+  EXPECT_EQ(1, parser.voip_metric()->num_packets());
+  EXPECT_EQ(kRemoteSsrc, parser.voip_metric()->Ssrc());
+  EXPECT_EQ(1, parser.voip_metric()->LossRate());
+  EXPECT_EQ(2, parser.voip_metric()->DiscardRate());
+  EXPECT_EQ(3, parser.voip_metric()->BurstDensity());
+  EXPECT_EQ(4, parser.voip_metric()->GapDensity());
+  EXPECT_EQ(0x1111, parser.voip_metric()->BurstDuration());
+  EXPECT_EQ(0x2222, parser.voip_metric()->GapDuration());
+  EXPECT_EQ(0x3333, parser.voip_metric()->RoundTripDelay());
+  EXPECT_EQ(0x4444, parser.voip_metric()->EndSystemDelay());
+  EXPECT_EQ(5, parser.voip_metric()->SignalLevel());
+  EXPECT_EQ(6, parser.voip_metric()->NoiseLevel());
+  EXPECT_EQ(7, parser.voip_metric()->Rerl());
+  EXPECT_EQ(8, parser.voip_metric()->Gmin());
+  EXPECT_EQ(9, parser.voip_metric()->Rfactor());
+  EXPECT_EQ(10, parser.voip_metric()->ExtRfactor());
+  EXPECT_EQ(11, parser.voip_metric()->MosLq());
+  EXPECT_EQ(12, parser.voip_metric()->MosCq());
+  EXPECT_EQ(13, parser.voip_metric()->RxConfig());
+  EXPECT_EQ(0x5555, parser.voip_metric()->JbNominal());
+  EXPECT_EQ(0x6666, parser.voip_metric()->JbMax());
+  EXPECT_EQ(0x7777, parser.voip_metric()->JbAbsMax());
+}
+
+TEST(RtcpPacketTest, XrWithMultipleReportBlocks) {
+  Rrtr rrtr;
+  Dlrr dlrr;
+  dlrr.WithDlrrItem(1, 2, 3);
+  VoipMetric metric;
+  Xr xr;
+  xr.From(kSenderSsrc);
+  xr.WithRrtr(&rrtr);
+  xr.WithDlrr(&dlrr);
+  xr.WithVoipMetric(&metric);
+
+  RawPacket packet = xr.Build();
+  RtcpPacketParser parser;
+  parser.Parse(packet.buffer(), packet.buffer_length());
+  EXPECT_EQ(1, parser.xr_header()->num_packets());
+  EXPECT_EQ(kSenderSsrc, parser.xr_header()->Ssrc());
+  EXPECT_EQ(1, parser.rrtr()->num_packets());
+  EXPECT_EQ(1, parser.dlrr()->num_packets());
+  EXPECT_EQ(1, parser.dlrr_items()->num_packets());
+  EXPECT_EQ(1, parser.voip_metric()->num_packets());
+}
+
+TEST(RtcpPacketTest, DlrrWithoutItemNotIncludedInPacket) {
+  Rrtr rrtr;
+  Dlrr dlrr;
+  VoipMetric metric;
+  Xr xr;
+  xr.From(kSenderSsrc);
+  xr.WithRrtr(&rrtr);
+  xr.WithDlrr(&dlrr);
+  xr.WithVoipMetric(&metric);
+
+  RawPacket packet = xr.Build();
+  RtcpPacketParser parser;
+  parser.Parse(packet.buffer(), packet.buffer_length());
+  EXPECT_EQ(1, parser.xr_header()->num_packets());
+  EXPECT_EQ(kSenderSsrc, parser.xr_header()->Ssrc());
+  EXPECT_EQ(1, parser.rrtr()->num_packets());
+  EXPECT_EQ(0, parser.dlrr()->num_packets());
+  EXPECT_EQ(1, parser.voip_metric()->num_packets());
+}
 }  // namespace webrtc
diff --git a/webrtc/test/rtcp_packet_parser.cc b/webrtc/test/rtcp_packet_parser.cc
index 69c50d1..558bee3 100644
--- a/webrtc/test/rtcp_packet_parser.cc
+++ b/webrtc/test/rtcp_packet_parser.cc
@@ -80,6 +80,41 @@
       case RTCPUtility::kRtcpRtpfbNackItemCode:
         nack_item_.Set(parser.Packet().NACKItem);
         break;
+      case RTCPUtility::kRtcpPsfbAppCode:
+        psfb_app_.Set(parser.Packet().PSFBAPP);
+        break;
+      case RTCPUtility::kRtcpPsfbRembItemCode:
+        remb_item_.Set(parser.Packet().REMBItem);
+        break;
+      case RTCPUtility::kRtcpRtpfbTmmbrCode:
+        tmmbr_.Set(parser.Packet().TMMBR);
+        break;
+      case RTCPUtility::kRtcpRtpfbTmmbrItemCode:
+        tmmbr_item_.Set(parser.Packet().TMMBRItem);
+        break;
+      case RTCPUtility::kRtcpRtpfbTmmbnCode:
+        tmmbn_.Set(parser.Packet().TMMBN);
+        tmmbn_items_.Clear();
+        break;
+      case RTCPUtility::kRtcpRtpfbTmmbnItemCode:
+        tmmbn_items_.Set(parser.Packet().TMMBNItem);
+        break;
+      case RTCPUtility::kRtcpXrHeaderCode:
+        xr_header_.Set(parser.Packet().XR);
+        dlrr_items_.Clear();
+        break;
+      case RTCPUtility::kRtcpXrReceiverReferenceTimeCode:
+        rrtr_.Set(parser.Packet().XRReceiverReferenceTimeItem);
+        break;
+      case RTCPUtility::kRtcpXrDlrrReportBlockCode:
+        dlrr_.Set();
+        break;
+      case RTCPUtility::kRtcpXrDlrrReportBlockItemCode:
+        dlrr_items_.Set(parser.Packet().XRDLRRReportBlockItem);
+        break;
+      case RTCPUtility::kRtcpXrVoipMetricCode:
+        voip_metric_.Set(parser.Packet().XRVOIPMetricItem);
+        break;
       default:
         break;
     }
diff --git a/webrtc/test/rtcp_packet_parser.h b/webrtc/test/rtcp_packet_parser.h
index a09674f..f7d36ba 100644
--- a/webrtc/test/rtcp_packet_parser.h
+++ b/webrtc/test/rtcp_packet_parser.h
@@ -378,6 +378,254 @@
   std::vector<uint16_t> last_nack_list_;
 };
 
+class PsfbApp : public PacketType {
+ public:
+  PsfbApp() {}
+  virtual ~PsfbApp() {}
+
+  uint32_t Ssrc() const { return psfb_app_.SenderSSRC; }
+
+ private:
+  friend class RtcpPacketParser;
+
+  void Set(const RTCPUtility::RTCPPacketPSFBAPP& psfb_app) {
+    psfb_app_ = psfb_app;
+    ++num_packets_;
+  }
+
+  RTCPUtility::RTCPPacketPSFBAPP psfb_app_;
+};
+
+class RembItem : public PacketType {
+ public:
+  RembItem() : last_bitrate_bps_(0) {}
+  virtual ~RembItem() {}
+
+  int last_bitrate_bps() const { return last_bitrate_bps_; }
+  std::vector<uint32_t> last_ssrc_list() {
+    return last_ssrc_list_;
+  }
+
+ private:
+  friend class RtcpPacketParser;
+
+  void Set(const RTCPUtility::RTCPPacketPSFBREMBItem& remb_item) {
+    last_bitrate_bps_ = remb_item.BitRate;
+    last_ssrc_list_.clear();
+    last_ssrc_list_.insert(
+        last_ssrc_list_.end(),
+        remb_item.SSRCs,
+        remb_item.SSRCs + remb_item.NumberOfSSRCs);
+    ++num_packets_;
+  }
+
+  uint32_t last_bitrate_bps_;
+  std::vector<uint32_t> last_ssrc_list_;
+};
+
+class Tmmbr : public PacketType {
+ public:
+  Tmmbr() {}
+  virtual ~Tmmbr() {}
+
+  uint32_t Ssrc() const { return tmmbr_.SenderSSRC; }
+
+ private:
+  friend class RtcpPacketParser;
+
+  void Set(const RTCPUtility::RTCPPacketRTPFBTMMBR& tmmbr) {
+    tmmbr_ = tmmbr;
+    ++num_packets_;
+  }
+
+  RTCPUtility::RTCPPacketRTPFBTMMBR tmmbr_;
+};
+
+class TmmbrItem : public PacketType {
+ public:
+  TmmbrItem() {}
+  virtual ~TmmbrItem() {}
+
+  uint32_t Ssrc() const { return tmmbr_item_.SSRC; }
+  uint32_t BitrateKbps() const { return tmmbr_item_.MaxTotalMediaBitRate; }
+  uint32_t Overhead() const { return tmmbr_item_.MeasuredOverhead; }
+
+ private:
+  friend class RtcpPacketParser;
+
+  void Set(const RTCPUtility::RTCPPacketRTPFBTMMBRItem& tmmbr_item) {
+    tmmbr_item_ = tmmbr_item;
+    ++num_packets_;
+  }
+
+  RTCPUtility::RTCPPacketRTPFBTMMBRItem tmmbr_item_;
+};
+
+
+class Tmmbn : public PacketType {
+ public:
+  Tmmbn() {}
+  virtual ~Tmmbn() {}
+
+  uint32_t Ssrc() const { return tmmbn_.SenderSSRC; }
+
+ private:
+  friend class RtcpPacketParser;
+
+  void Set(const RTCPUtility::RTCPPacketRTPFBTMMBN& tmmbn) {
+    tmmbn_ = tmmbn;
+    ++num_packets_;
+  }
+
+  RTCPUtility::RTCPPacketRTPFBTMMBN tmmbn_;
+};
+
+class TmmbnItems : public PacketType {
+ public:
+  TmmbnItems() {}
+  virtual ~TmmbnItems() {}
+
+  uint32_t Ssrc(uint8_t num) const {
+    assert(num < tmmbns_.size());
+    return tmmbns_[num].SSRC;
+  }
+  uint32_t BitrateKbps(uint8_t num) const {
+    assert(num < tmmbns_.size());
+    return tmmbns_[num].MaxTotalMediaBitRate;
+  }
+  uint32_t Overhead(uint8_t num) const {
+    assert(num < tmmbns_.size());
+    return tmmbns_[num].MeasuredOverhead;
+  }
+
+ private:
+  friend class RtcpPacketParser;
+
+  void Set(const RTCPUtility::RTCPPacketRTPFBTMMBNItem& tmmbn_item) {
+    tmmbns_.push_back(tmmbn_item);
+    ++num_packets_;
+  }
+  void Clear() { tmmbns_.clear(); }
+
+  std::vector<RTCPUtility::RTCPPacketRTPFBTMMBNItem> tmmbns_;
+};
+
+class XrHeader : public PacketType {
+ public:
+  XrHeader() {}
+  virtual ~XrHeader() {}
+
+  uint32_t Ssrc() const { return xr_header_.OriginatorSSRC; }
+
+ private:
+  friend class RtcpPacketParser;
+
+  void Set(const RTCPUtility::RTCPPacketXR& xr_header) {
+    xr_header_ = xr_header;
+    ++num_packets_;
+  }
+
+  RTCPUtility::RTCPPacketXR xr_header_;
+};
+
+class Rrtr : public PacketType {
+ public:
+  Rrtr() {}
+  virtual ~Rrtr() {}
+
+  uint32_t NtpSec() const { return rrtr_.NTPMostSignificant; }
+  uint32_t NtpFrac() const { return rrtr_.NTPLeastSignificant; }
+
+ private:
+  friend class RtcpPacketParser;
+
+  void Set(const RTCPUtility::RTCPPacketXRReceiverReferenceTimeItem& rrtr) {
+    rrtr_ = rrtr;
+    ++num_packets_;
+  }
+
+  RTCPUtility::RTCPPacketXRReceiverReferenceTimeItem rrtr_;
+};
+
+class Dlrr : public PacketType {
+ public:
+  Dlrr() {}
+  virtual ~Dlrr() {}
+
+ private:
+  friend class RtcpPacketParser;
+
+  void Set() { ++num_packets_; }
+};
+
+class DlrrItems : public PacketType {
+ public:
+  DlrrItems() {}
+  virtual ~DlrrItems() {}
+
+  uint32_t Ssrc(uint8_t num) const {
+    assert(num < dlrrs_.size());
+    return dlrrs_[num].SSRC;
+  }
+  uint32_t LastRr(uint8_t num) const {
+    assert(num < dlrrs_.size());
+    return dlrrs_[num].LastRR;
+  }
+  uint32_t DelayLastRr(uint8_t num) const {
+    assert(num < dlrrs_.size());
+    return dlrrs_[num].DelayLastRR;
+  }
+
+ private:
+  friend class RtcpPacketParser;
+
+  void Set(const RTCPUtility::RTCPPacketXRDLRRReportBlockItem& dlrr) {
+    dlrrs_.push_back(dlrr);
+    ++num_packets_;
+  }
+  void Clear() { dlrrs_.clear(); }
+
+  std::vector<RTCPUtility::RTCPPacketXRDLRRReportBlockItem> dlrrs_;
+};
+
+class VoipMetric : public PacketType {
+ public:
+  VoipMetric() {}
+  virtual ~VoipMetric() {}
+
+  uint32_t Ssrc() const { return voip_metric_.SSRC; }
+  uint8_t LossRate() { return voip_metric_.lossRate; }
+  uint8_t DiscardRate() { return voip_metric_.discardRate; }
+  uint8_t BurstDensity() { return voip_metric_.burstDensity; }
+  uint8_t GapDensity() { return voip_metric_.gapDensity; }
+  uint16_t BurstDuration() { return voip_metric_.burstDuration; }
+  uint16_t GapDuration() { return voip_metric_.gapDuration; }
+  uint16_t RoundTripDelay() { return voip_metric_.roundTripDelay; }
+  uint16_t EndSystemDelay() { return voip_metric_.endSystemDelay; }
+  uint8_t SignalLevel() { return voip_metric_.signalLevel; }
+  uint8_t NoiseLevel() { return voip_metric_.noiseLevel; }
+  uint8_t Rerl() { return voip_metric_.RERL; }
+  uint8_t Gmin() { return voip_metric_.Gmin; }
+  uint8_t Rfactor() { return voip_metric_.Rfactor; }
+  uint8_t ExtRfactor() { return voip_metric_.extRfactor; }
+  uint8_t MosLq() { return voip_metric_.MOSLQ; }
+  uint8_t MosCq() { return voip_metric_.MOSCQ; }
+  uint8_t RxConfig() { return voip_metric_.RXconfig; }
+  uint16_t JbNominal() { return voip_metric_.JBnominal; }
+  uint16_t JbMax() { return voip_metric_.JBmax; }
+  uint16_t JbAbsMax() { return voip_metric_.JBabsMax; }
+
+ private:
+  friend class RtcpPacketParser;
+
+  void Set(const RTCPUtility::RTCPPacketXRVOIPMetricItem& voip_metric) {
+    voip_metric_ = voip_metric;
+    ++num_packets_;
+  }
+
+  RTCPUtility::RTCPPacketXRVOIPMetricItem voip_metric_;
+};
+
 class RtcpPacketParser {
  public:
   RtcpPacketParser();
@@ -403,6 +651,17 @@
   FirItem* fir_item() { return &fir_item_; }
   Nack* nack() { return &nack_; }
   NackItem* nack_item() { return &nack_item_; }
+  PsfbApp* psfb_app() { return &psfb_app_; }
+  RembItem* remb_item() { return &remb_item_; }
+  Tmmbr* tmmbr() { return &tmmbr_; }
+  TmmbrItem* tmmbr_item() { return &tmmbr_item_; }
+  Tmmbn* tmmbn() { return &tmmbn_; }
+  TmmbnItems* tmmbn_items() { return &tmmbn_items_; }
+  XrHeader* xr_header() { return &xr_header_; }
+  Rrtr* rrtr() { return &rrtr_; }
+  Dlrr* dlrr() { return &dlrr_; }
+  DlrrItems* dlrr_items() { return &dlrr_items_; }
+  VoipMetric* voip_metric() { return &voip_metric_; }
 
   int report_blocks_per_ssrc(uint32_t ssrc) {
     return report_blocks_per_ssrc_[ssrc];
@@ -427,6 +686,17 @@
   FirItem fir_item_;
   Nack nack_;
   NackItem nack_item_;
+  PsfbApp psfb_app_;
+  RembItem remb_item_;
+  Tmmbr tmmbr_;
+  TmmbrItem tmmbr_item_;
+  Tmmbn tmmbn_;
+  TmmbnItems tmmbn_items_;
+  XrHeader xr_header_;
+  Rrtr rrtr_;
+  Dlrr dlrr_;
+  DlrrItems dlrr_items_;
+  VoipMetric voip_metric_;
 
   std::map<uint32_t, int> report_blocks_per_ssrc_;
 };