[rtp_rtcp] rtcp::SenderReport moved into own file and got Parse function

BUG=webrtc:5260
R=åsapersson

Review URL: https://codereview.webrtc.org/1544983002

Cr-Commit-Position: refs/heads/master@{#11288}
diff --git a/webrtc/call/rtc_event_log_unittest.cc b/webrtc/call/rtc_event_log_unittest.cc
index f590f66..0998071 100644
--- a/webrtc/call/rtc_event_log_unittest.cc
+++ b/webrtc/call/rtc_event_log_unittest.cc
@@ -23,6 +23,7 @@
 #include "webrtc/call.h"
 #include "webrtc/call/rtc_event_log.h"
 #include "webrtc/modules/rtp_rtcp/source/rtcp_packet.h"
+#include "webrtc/modules/rtp_rtcp/source/rtcp_packet/sender_report.h"
 #include "webrtc/modules/rtp_rtcp/source/rtp_sender.h"
 #include "webrtc/system_wrappers/include/clock.h"
 #include "webrtc/test/test_suite.h"
@@ -355,8 +356,8 @@
 
   rtcp::SenderReport sender_report;
   sender_report.From(prng->Rand<uint32_t>());  // Sender SSRC.
-  sender_report.WithNtpSec(prng->Rand<uint32_t>());
-  sender_report.WithNtpFrac(prng->Rand<uint32_t>());
+  sender_report.WithNtp(
+      NtpTime(prng->Rand<uint32_t>(), prng->Rand<uint32_t>()));
   sender_report.WithPacketCount(prng->Rand<uint32_t>());
   sender_report.WithReportBlock(report_block);
 
diff --git a/webrtc/modules/modules.gyp b/webrtc/modules/modules.gyp
index 37d4304..9c50d26 100644
--- a/webrtc/modules/modules.gyp
+++ b/webrtc/modules/modules.gyp
@@ -320,6 +320,7 @@
                 'rtp_rtcp/source/rtcp_packet/rpsi_unittest.cc',
                 'rtp_rtcp/source/rtcp_packet/rrtr_unittest.cc',
                 'rtp_rtcp/source/rtcp_packet/sdes_unittest.cc',
+                'rtp_rtcp/source/rtcp_packet/sender_report_unittest.cc',
                 'rtp_rtcp/source/rtcp_packet/sli_unittest.cc',
                 'rtp_rtcp/source/rtcp_packet/tmmbn_unittest.cc',
                 'rtp_rtcp/source/rtcp_packet/tmmbr_unittest.cc',
diff --git a/webrtc/modules/rtp_rtcp/BUILD.gn b/webrtc/modules/rtp_rtcp/BUILD.gn
index 42de871..f423d08 100644
--- a/webrtc/modules/rtp_rtcp/BUILD.gn
+++ b/webrtc/modules/rtp_rtcp/BUILD.gn
@@ -80,6 +80,8 @@
     "source/rtcp_packet/rtpfb.h",
     "source/rtcp_packet/sdes.cc",
     "source/rtcp_packet/sdes.h",
+    "source/rtcp_packet/sender_report.cc",
+    "source/rtcp_packet/sender_report.h",
     "source/rtcp_packet/sli.cc",
     "source/rtcp_packet/sli.h",
     "source/rtcp_packet/tmmbn.cc",
diff --git a/webrtc/modules/rtp_rtcp/rtp_rtcp.gypi b/webrtc/modules/rtp_rtcp/rtp_rtcp.gypi
index 1db0441..a927e4e 100644
--- a/webrtc/modules/rtp_rtcp/rtp_rtcp.gypi
+++ b/webrtc/modules/rtp_rtcp/rtp_rtcp.gypi
@@ -75,6 +75,8 @@
         'source/rtcp_packet/rtpfb.h',
         'source/rtcp_packet/sdes.cc',
         'source/rtcp_packet/sdes.h',
+        'source/rtcp_packet/sender_report.cc',
+        'source/rtcp_packet/sender_report.h',
         'source/rtcp_packet/sli.cc',
         'source/rtcp_packet/sli.h',
         'source/rtcp_packet/tmmbn.cc',
diff --git a/webrtc/modules/rtp_rtcp/source/rtcp_packet.cc b/webrtc/modules/rtp_rtcp/source/rtcp_packet.cc
index ec87ed6..eaaa78c 100644
--- a/webrtc/modules/rtp_rtcp/source/rtcp_packet.cc
+++ b/webrtc/modules/rtp_rtcp/source/rtcp_packet.cc
@@ -10,23 +10,10 @@
 
 #include "webrtc/modules/rtp_rtcp/source/rtcp_packet.h"
 
-#include <algorithm>
-
 #include "webrtc/base/checks.h"
 #include "webrtc/base/logging.h"
 #include "webrtc/modules/rtp_rtcp/source/byte_io.h"
 
-using webrtc::RTCPUtility::PT_APP;
-using webrtc::RTCPUtility::PT_IJ;
-using webrtc::RTCPUtility::PT_RTPFB;
-using webrtc::RTCPUtility::PT_SR;
-
-using webrtc::RTCPUtility::RTCPPacketAPP;
-using webrtc::RTCPUtility::RTCPPacketReportBlockItem;
-using webrtc::RTCPUtility::RTCPPacketRTPFBNACK;
-using webrtc::RTCPUtility::RTCPPacketRTPFBNACKItem;
-using webrtc::RTCPUtility::RTCPPacketSR;
-
 namespace webrtc {
 namespace rtcp {
 namespace {
@@ -37,66 +24,6 @@
   ByteWriter<uint16_t>::WriteBigEndian(buffer + *offset, value);
   *offset += 2;
 }
-void AssignUWord32(uint8_t* buffer, size_t* offset, uint32_t value) {
-  ByteWriter<uint32_t>::WriteBigEndian(buffer + *offset, value);
-  *offset += 4;
-}
-
-//  Sender report (SR) (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|    RC   |   PT=SR=200   |             length            |
-//  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
-//  |                         SSRC of sender                        |
-//  +=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+
-//  |              NTP timestamp, most significant word             |
-//  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
-//  |             NTP timestamp, least significant word             |
-//  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
-//  |                         RTP timestamp                         |
-//  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
-//  |                     sender's packet count                     |
-//  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
-//  |                      sender's octet count                     |
-//  +=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+
-
-void CreateSenderReport(const RTCPPacketSR& sr,
-                        uint8_t* buffer,
-                        size_t* pos) {
-  AssignUWord32(buffer, pos, sr.SenderSSRC);
-  AssignUWord32(buffer, pos, sr.NTPMostSignificant);
-  AssignUWord32(buffer, pos, sr.NTPLeastSignificant);
-  AssignUWord32(buffer, pos, sr.RTPTimestamp);
-  AssignUWord32(buffer, pos, sr.SenderPacketCount);
-  AssignUWord32(buffer, pos, sr.SenderOctetCount);
-}
-
-//  Report block (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
-//  +=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+
-//  |                 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)                  |
-//  +=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+
-
-void CreateReportBlocks(const std::vector<ReportBlock>& blocks,
-                        uint8_t* buffer,
-                        size_t* pos) {
-  for (const ReportBlock& block : blocks) {
-    block.Create(buffer + *pos);
-    *pos += ReportBlock::kLength;
-  }
-}
 }  // namespace
 
 void RtcpPacket::Append(RtcpPacket* packet) {
@@ -195,30 +122,6 @@
   AssignUWord16(buffer, pos, length);
 }
 
-bool SenderReport::Create(uint8_t* packet,
-                          size_t* index,
-                          size_t max_length,
-                          RtcpPacket::PacketReadyCallback* callback) const {
-  while (*index + BlockLength() > max_length) {
-    if (!OnBufferFull(packet, index, callback))
-      return false;
-  }
-  CreateHeader(sr_.NumberOfReportBlocks, PT_SR, HeaderLength(), packet, index);
-  CreateSenderReport(sr_, packet, index);
-  CreateReportBlocks(report_blocks_, packet, index);
-  return true;
-}
-
-bool SenderReport::WithReportBlock(const ReportBlock& block) {
-  if (report_blocks_.size() >= kMaxNumberOfReportBlocks) {
-    LOG(LS_WARNING) << "Max report blocks reached.";
-    return false;
-  }
-  report_blocks_.push_back(block);
-  sr_.NumberOfReportBlocks = report_blocks_.size();
-  return true;
-}
-
 RawPacket::RawPacket(size_t buffer_length)
     : buffer_length_(buffer_length), length_(0) {
   buffer_.reset(new uint8_t[buffer_length]);
diff --git a/webrtc/modules/rtp_rtcp/source/rtcp_packet.h b/webrtc/modules/rtp_rtcp/source/rtcp_packet.h
index 2cf9005..965a667 100644
--- a/webrtc/modules/rtp_rtcp/source/rtcp_packet.h
+++ b/webrtc/modules/rtp_rtcp/source/rtcp_packet.h
@@ -15,8 +15,6 @@
 #include <vector>
 
 #include "webrtc/base/scoped_ptr.h"
-#include "webrtc/modules/rtp_rtcp/include/rtp_rtcp_defines.h"
-#include "webrtc/modules/rtp_rtcp/source/rtcp_packet/report_block.h"
 #include "webrtc/modules/rtp_rtcp/source/rtcp_utility.h"
 #include "webrtc/typedefs.h"
 
@@ -24,7 +22,6 @@
 namespace rtcp {
 
 static const int kCommonFbFmtLength = 12;
-static const int kReportBlockLength = 24;
 
 class RawPacket;
 
@@ -120,79 +117,6 @@
                             PacketReadyCallback* callback) const;
 };
 
-// TODO(sprang): Move RtcpPacket subclasses out to separate files.
-
-// 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
-//  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
-//  |V=2|P|    RC   |   PT=SR=200   |             length            |
-//  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
-//  |                         SSRC of sender                        |
-//  +=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+
-//  |              NTP timestamp, most significant word             |
-//  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
-//  |             NTP timestamp, least significant word             |
-//  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
-//  |                         RTP timestamp                         |
-//  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
-//  |                     sender's packet count                     |
-//  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
-//  |                      sender's octet count                     |
-//  +=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+
-//  |                         report block(s)                       |
-//  |                            ....                               |
-
-class SenderReport : public RtcpPacket {
- public:
-  SenderReport() : RtcpPacket() {
-    memset(&sr_, 0, sizeof(sr_));
-  }
-
-  virtual ~SenderReport() {}
-
-  void From(uint32_t ssrc) {
-    sr_.SenderSSRC = ssrc;
-  }
-  void WithNtpSec(uint32_t sec) {
-    sr_.NTPMostSignificant = sec;
-  }
-  void WithNtpFrac(uint32_t frac) {
-    sr_.NTPLeastSignificant = frac;
-  }
-  void WithRtpTimestamp(uint32_t rtp_timestamp) {
-    sr_.RTPTimestamp = rtp_timestamp;
-  }
-  void WithPacketCount(uint32_t packet_count) {
-    sr_.SenderPacketCount = packet_count;
-  }
-  void WithOctetCount(uint32_t octet_count) {
-    sr_.SenderOctetCount = octet_count;
-  }
-  bool WithReportBlock(const ReportBlock& block);
-
- protected:
-  bool Create(uint8_t* packet,
-              size_t* index,
-              size_t max_length,
-              RtcpPacket::PacketReadyCallback* callback) const override;
-
- private:
-  static const int 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_;
-
-  RTC_DISALLOW_COPY_AND_ASSIGN(SenderReport);
-};
-
 // Class holding a RTCP packet.
 //
 // Takes a built rtcp packet.
diff --git a/webrtc/modules/rtp_rtcp/source/rtcp_packet/compound_packet_unittest.cc b/webrtc/modules/rtp_rtcp/source/rtcp_packet/compound_packet_unittest.cc
index b38b69c..0378566 100644
--- a/webrtc/modules/rtp_rtcp/source/rtcp_packet/compound_packet_unittest.cc
+++ b/webrtc/modules/rtp_rtcp/source/rtcp_packet/compound_packet_unittest.cc
@@ -15,6 +15,7 @@
 #include "webrtc/modules/rtp_rtcp/source/rtcp_packet/bye.h"
 #include "webrtc/modules/rtp_rtcp/source/rtcp_packet/fir.h"
 #include "webrtc/modules/rtp_rtcp/source/rtcp_packet/receiver_report.h"
+#include "webrtc/modules/rtp_rtcp/source/rtcp_packet/sender_report.h"
 #include "webrtc/test/rtcp_packet_parser.h"
 
 using webrtc::rtcp::Bye;
diff --git a/webrtc/modules/rtp_rtcp/source/rtcp_packet/sender_report.cc b/webrtc/modules/rtp_rtcp/source/rtcp_packet/sender_report.cc
new file mode 100644
index 0000000..ab1863e
--- /dev/null
+++ b/webrtc/modules/rtp_rtcp/source/rtcp_packet/sender_report.cc
@@ -0,0 +1,118 @@
+/*
+ *  Copyright (c) 2016 The WebRTC project authors. All Rights Reserved.
+ *
+ *  Use of this source code is governed by a BSD-style license
+ *  that can be found in the LICENSE file in the root of the source
+ *  tree. An additional intellectual property rights grant can be found
+ *  in the file PATENTS.  All contributing project authors may
+ *  be found in the AUTHORS file in the root of the source tree.
+ */
+
+#include "webrtc/modules/rtp_rtcp/source/rtcp_packet/sender_report.h"
+
+#include "webrtc/base/checks.h"
+#include "webrtc/base/logging.h"
+#include "webrtc/modules/rtp_rtcp/source/byte_io.h"
+
+using webrtc::RTCPUtility::RtcpCommonHeader;
+
+namespace webrtc {
+namespace rtcp {
+//    Sender report (SR) (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|    RC   |   PT=SR=200   |             length            |
+//    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+//  0 |                         SSRC of sender                        |
+//    +=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+
+//  4 |              NTP timestamp, most significant word             |
+//    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+//  8 |             NTP timestamp, least significant word             |
+//    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+// 12 |                         RTP timestamp                         |
+//    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+// 16 |                     sender's packet count                     |
+//    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+// 20 |                      sender's octet count                     |
+// 24 +=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+
+
+SenderReport::SenderReport()
+    : sender_ssrc_(0),
+      rtp_timestamp_(0),
+      sender_packet_count_(0),
+      sender_octet_count_(0) {}
+
+bool SenderReport::Parse(const RtcpCommonHeader& header,
+                         const uint8_t* payload) {
+  RTC_DCHECK(header.packet_type == kPacketType);
+
+  const uint8_t report_block_count = header.count_or_format;
+  if (header.payload_size_bytes <
+      kSenderBaseLength + report_block_count * ReportBlock::kLength) {
+    LOG(LS_WARNING) << "Packet is too small to contain all the data.";
+    return false;
+  }
+  // Read SenderReport header.
+  sender_ssrc_ = ByteReader<uint32_t>::ReadBigEndian(&payload[0]);
+  uint32_t secs = ByteReader<uint32_t>::ReadBigEndian(&payload[4]);
+  uint32_t frac = ByteReader<uint32_t>::ReadBigEndian(&payload[8]);
+  ntp_.Set(secs, frac);
+  rtp_timestamp_ = ByteReader<uint32_t>::ReadBigEndian(&payload[12]);
+  sender_packet_count_ = ByteReader<uint32_t>::ReadBigEndian(&payload[16]);
+  sender_octet_count_ = ByteReader<uint32_t>::ReadBigEndian(&payload[20]);
+  report_blocks_.resize(report_block_count);
+  const uint8_t* next_block = payload + kSenderBaseLength;
+  for (ReportBlock& block : report_blocks_) {
+    bool block_parsed = block.Parse(next_block, ReportBlock::kLength);
+    RTC_DCHECK(block_parsed);
+    next_block += ReportBlock::kLength;
+  }
+  // Double check we didn't read beyond provided buffer.
+  RTC_DCHECK_LE(next_block, payload + header.payload_size_bytes);
+  return true;
+}
+
+bool SenderReport::Create(uint8_t* packet,
+                          size_t* index,
+                          size_t max_length,
+                          RtcpPacket::PacketReadyCallback* callback) const {
+  while (*index + BlockLength() > max_length) {
+    if (!OnBufferFull(packet, index, callback))
+      return false;
+  }
+  const size_t index_end = *index + BlockLength();
+
+  CreateHeader(report_blocks_.size(), kPacketType, HeaderLength(), packet,
+               index);
+  // Write SenderReport header.
+  ByteWriter<uint32_t>::WriteBigEndian(&packet[*index + 0], sender_ssrc_);
+  ByteWriter<uint32_t>::WriteBigEndian(&packet[*index + 4], ntp_.seconds());
+  ByteWriter<uint32_t>::WriteBigEndian(&packet[*index + 8], ntp_.fractions());
+  ByteWriter<uint32_t>::WriteBigEndian(&packet[*index + 12], rtp_timestamp_);
+  ByteWriter<uint32_t>::WriteBigEndian(&packet[*index + 16],
+                                       sender_packet_count_);
+  ByteWriter<uint32_t>::WriteBigEndian(&packet[*index + 20],
+                                       sender_octet_count_);
+  *index += kSenderBaseLength;
+  // Write report blocks.
+  for (const ReportBlock& block : report_blocks_) {
+    block.Create(packet + *index);
+    *index += ReportBlock::kLength;
+  }
+  // Ensure bytes written match expected.
+  RTC_DCHECK_EQ(*index, index_end);
+  return true;
+}
+
+bool SenderReport::WithReportBlock(const ReportBlock& block) {
+  if (report_blocks_.size() >= kMaxNumberOfReportBlocks) {
+    LOG(LS_WARNING) << "Max report blocks reached.";
+    return false;
+  }
+  report_blocks_.push_back(block);
+  return true;
+}
+
+}  // namespace rtcp
+}  // namespace webrtc
diff --git a/webrtc/modules/rtp_rtcp/source/rtcp_packet/sender_report.h b/webrtc/modules/rtp_rtcp/source/rtcp_packet/sender_report.h
new file mode 100644
index 0000000..e26911a
--- /dev/null
+++ b/webrtc/modules/rtp_rtcp/source/rtcp_packet/sender_report.h
@@ -0,0 +1,86 @@
+/*
+ *  Copyright (c) 2016 The WebRTC project authors. All Rights Reserved.
+ *
+ *  Use of this source code is governed by a BSD-style license
+ *  that can be found in the LICENSE file in the root of the source
+ *  tree. An additional intellectual property rights grant can be found
+ *  in the file PATENTS.  All contributing project authors may
+ *  be found in the AUTHORS file in the root of the source tree.
+ */
+
+#ifndef WEBRTC_MODULES_RTP_RTCP_SOURCE_RTCP_PACKET_SENDER_REPORT_H_
+#define WEBRTC_MODULES_RTP_RTCP_SOURCE_RTCP_PACKET_SENDER_REPORT_H_
+
+#include <vector>
+
+#include "webrtc/modules/rtp_rtcp/source/rtcp_packet.h"
+#include "webrtc/modules/rtp_rtcp/source/rtcp_packet/report_block.h"
+#include "webrtc/modules/rtp_rtcp/source/rtcp_utility.h"
+#include "webrtc/system_wrappers/include/ntp_time.h"
+
+namespace webrtc {
+namespace rtcp {
+
+class SenderReport : public RtcpPacket {
+ public:
+  static const uint8_t kPacketType = 200;
+
+  SenderReport();
+  virtual ~SenderReport() {}
+
+  // Parse assumes header is already parsed and validated.
+  bool Parse(const RTCPUtility::RtcpCommonHeader& header,
+             const uint8_t* payload);  // Size of the payload is in the header.
+
+  void From(uint32_t ssrc) { sender_ssrc_ = ssrc; }
+  void WithNtp(NtpTime ntp) { ntp_ = ntp; }
+  void WithRtpTimestamp(uint32_t rtp_timestamp) {
+    rtp_timestamp_ = rtp_timestamp;
+  }
+  void WithPacketCount(uint32_t packet_count) {
+    sender_packet_count_ = packet_count;
+  }
+  void WithOctetCount(uint32_t octet_count) {
+    sender_octet_count_ = octet_count;
+  }
+  bool WithReportBlock(const ReportBlock& block);
+  void ClearReportBlocks() { report_blocks_.clear(); }
+
+  uint32_t sender_ssrc() const { return sender_ssrc_; }
+  NtpTime ntp() const { return ntp_; }
+  uint32_t rtp_timestamp() const { return rtp_timestamp_; }
+  uint32_t sender_packet_count() const { return sender_packet_count_; }
+  uint32_t sender_octet_count() const { return sender_octet_count_; }
+
+  const std::vector<ReportBlock>& report_blocks() const {
+    return report_blocks_;
+  }
+
+ protected:
+  bool Create(uint8_t* packet,
+              size_t* index,
+              size_t max_length,
+              RtcpPacket::PacketReadyCallback* callback) const override;
+
+ private:
+  static const size_t kMaxNumberOfReportBlocks = 0x1f;
+  const size_t kSenderBaseLength = 24;
+
+  size_t BlockLength() const override {
+    return kHeaderLength + kSenderBaseLength +
+           report_blocks_.size() * ReportBlock::kLength;
+  }
+
+  uint32_t sender_ssrc_;
+  NtpTime ntp_;
+  uint32_t rtp_timestamp_;
+  uint32_t sender_packet_count_;
+  uint32_t sender_octet_count_;
+  std::vector<ReportBlock> report_blocks_;
+
+  RTC_DISALLOW_COPY_AND_ASSIGN(SenderReport);
+};
+
+}  // namespace rtcp
+}  // namespace webrtc
+#endif  // WEBRTC_MODULES_RTP_RTCP_SOURCE_RTCP_PACKET_SENDER_REPORT_H_
diff --git a/webrtc/modules/rtp_rtcp/source/rtcp_packet/sender_report_unittest.cc b/webrtc/modules/rtp_rtcp/source/rtcp_packet/sender_report_unittest.cc
new file mode 100644
index 0000000..548c130
--- /dev/null
+++ b/webrtc/modules/rtp_rtcp/source/rtcp_packet/sender_report_unittest.cc
@@ -0,0 +1,117 @@
+/*
+ *  Copyright (c) 2016 The WebRTC project authors. All Rights Reserved.
+ *
+ *  Use of this source code is governed by a BSD-style license
+ *  that can be found in the LICENSE file in the root of the source
+ *  tree. An additional intellectual property rights grant can be found
+ *  in the file PATENTS.  All contributing project authors may
+ *  be found in the AUTHORS file in the root of the source tree.
+ */
+
+#include "webrtc/modules/rtp_rtcp/source/rtcp_packet/sender_report.h"
+
+#include "testing/gtest/include/gtest/gtest.h"
+
+using webrtc::rtcp::RawPacket;
+using webrtc::rtcp::ReportBlock;
+using webrtc::rtcp::SenderReport;
+using webrtc::RTCPUtility::RtcpCommonHeader;
+using webrtc::RTCPUtility::RtcpParseCommonHeader;
+
+namespace webrtc {
+
+class RtcpPacketSenderReportTest : public ::testing::Test {
+ protected:
+  const uint32_t kSenderSsrc = 0x12345678;
+  const uint32_t kRemoteSsrc = 0x23456789;
+
+  void ParsePacket(const RawPacket& packet) {
+    RtcpCommonHeader header;
+    EXPECT_TRUE(
+        RtcpParseCommonHeader(packet.Buffer(), packet.Length(), &header));
+    EXPECT_EQ(packet.Length(), header.BlockSize());
+    EXPECT_TRUE(parsed_.Parse(
+        header, packet.Buffer() + RtcpCommonHeader::kHeaderSizeBytes));
+  }
+
+  // Only ParsePacket can change parsed, tests should use it in readonly mode.
+  const SenderReport& parsed() { return parsed_; }
+
+ private:
+  SenderReport parsed_;
+};
+
+TEST_F(RtcpPacketSenderReportTest, WithoutReportBlocks) {
+  const NtpTime kNtp(0x11121418, 0x22242628);
+  const uint32_t kRtpTimestamp = 0x33343536;
+  const uint32_t kPacketCount = 0x44454647;
+  const uint32_t kOctetCount = 0x55565758;
+
+  SenderReport sr;
+  sr.From(kSenderSsrc);
+  sr.WithNtp(kNtp);
+  sr.WithRtpTimestamp(kRtpTimestamp);
+  sr.WithPacketCount(kPacketCount);
+  sr.WithOctetCount(kOctetCount);
+
+  rtc::scoped_ptr<RawPacket> packet = sr.Build();
+  ParsePacket(*packet);
+
+  EXPECT_EQ(kSenderSsrc, parsed().sender_ssrc());
+  EXPECT_EQ(kNtp, parsed().ntp());
+  EXPECT_EQ(kRtpTimestamp, parsed().rtp_timestamp());
+  EXPECT_EQ(kPacketCount, parsed().sender_packet_count());
+  EXPECT_EQ(kOctetCount, parsed().sender_octet_count());
+  EXPECT_TRUE(parsed().report_blocks().empty());
+}
+
+TEST_F(RtcpPacketSenderReportTest, WithOneReportBlock) {
+  ReportBlock rb;
+  rb.To(kRemoteSsrc);
+
+  SenderReport sr;
+  sr.From(kSenderSsrc);
+  EXPECT_TRUE(sr.WithReportBlock(rb));
+
+  rtc::scoped_ptr<RawPacket> packet = sr.Build();
+  ParsePacket(*packet);
+
+  EXPECT_EQ(kSenderSsrc, parsed().sender_ssrc());
+  EXPECT_EQ(1u, parsed().report_blocks().size());
+  EXPECT_EQ(kRemoteSsrc, parsed().report_blocks()[0].source_ssrc());
+}
+
+TEST_F(RtcpPacketSenderReportTest, WithTwoReportBlocks) {
+  ReportBlock rb1;
+  rb1.To(kRemoteSsrc);
+  ReportBlock rb2;
+  rb2.To(kRemoteSsrc + 1);
+
+  SenderReport sr;
+  sr.From(kSenderSsrc);
+  EXPECT_TRUE(sr.WithReportBlock(rb1));
+  EXPECT_TRUE(sr.WithReportBlock(rb2));
+
+  rtc::scoped_ptr<RawPacket> packet = sr.Build();
+  ParsePacket(*packet);
+
+  EXPECT_EQ(kSenderSsrc, parsed().sender_ssrc());
+  EXPECT_EQ(2u, parsed().report_blocks().size());
+  EXPECT_EQ(kRemoteSsrc, parsed().report_blocks()[0].source_ssrc());
+  EXPECT_EQ(kRemoteSsrc + 1, parsed().report_blocks()[1].source_ssrc());
+}
+
+TEST_F(RtcpPacketSenderReportTest, WithTooManyReportBlocks) {
+  SenderReport sr;
+  sr.From(kSenderSsrc);
+  const size_t kMaxReportBlocks = (1 << 5) - 1;
+  ReportBlock rb;
+  for (size_t i = 0; i < kMaxReportBlocks; ++i) {
+    rb.To(kRemoteSsrc + i);
+    EXPECT_TRUE(sr.WithReportBlock(rb));
+  }
+  rb.To(kRemoteSsrc + kMaxReportBlocks);
+  EXPECT_FALSE(sr.WithReportBlock(rb));
+}
+
+}  // namespace webrtc
diff --git a/webrtc/modules/rtp_rtcp/source/rtcp_packet_unittest.cc b/webrtc/modules/rtp_rtcp/source/rtcp_packet_unittest.cc
index 6b4ef90..1b5d4f3 100644
--- a/webrtc/modules/rtp_rtcp/source/rtcp_packet_unittest.cc
+++ b/webrtc/modules/rtp_rtcp/source/rtcp_packet_unittest.cc
@@ -14,142 +14,14 @@
 #include "testing/gtest/include/gtest/gtest.h"
 
 #include "webrtc/modules/rtp_rtcp/source/rtcp_packet.h"
-#include "webrtc/modules/rtp_rtcp/source/rtcp_packet/app.h"
-#include "webrtc/modules/rtp_rtcp/source/rtcp_packet/bye.h"
 #include "webrtc/modules/rtp_rtcp/source/rtcp_packet/receiver_report.h"
-#include "webrtc/test/rtcp_packet_parser.h"
 
-using ::testing::ElementsAre;
-
-using webrtc::rtcp::App;
-using webrtc::rtcp::Bye;
-using webrtc::rtcp::RawPacket;
 using webrtc::rtcp::ReceiverReport;
 using webrtc::rtcp::ReportBlock;
-using webrtc::rtcp::SenderReport;
-using webrtc::test::RtcpPacketParser;
 
 namespace webrtc {
 
 const uint32_t kSenderSsrc = 0x12345678;
-const uint32_t kRemoteSsrc = 0x23456789;
-
-TEST(RtcpPacketTest, Sr) {
-  SenderReport sr;
-  sr.From(kSenderSsrc);
-  sr.WithNtpSec(0x11111111);
-  sr.WithNtpFrac(0x22222222);
-  sr.WithRtpTimestamp(0x33333333);
-  sr.WithPacketCount(0x44444444);
-  sr.WithOctetCount(0x55555555);
-
-  rtc::scoped_ptr<RawPacket> packet(sr.Build());
-  RtcpPacketParser parser;
-  parser.Parse(packet->Buffer(), packet->Length());
-
-  EXPECT_EQ(1, parser.sender_report()->num_packets());
-  EXPECT_EQ(kSenderSsrc, parser.sender_report()->Ssrc());
-  EXPECT_EQ(0x11111111U, parser.sender_report()->NtpSec());
-  EXPECT_EQ(0x22222222U, parser.sender_report()->NtpFrac());
-  EXPECT_EQ(0x33333333U, parser.sender_report()->RtpTimestamp());
-  EXPECT_EQ(0x44444444U, parser.sender_report()->PacketCount());
-  EXPECT_EQ(0x55555555U, parser.sender_report()->OctetCount());
-  EXPECT_EQ(0, parser.report_block()->num_packets());
-}
-
-TEST(RtcpPacketTest, SrWithOneReportBlock) {
-  ReportBlock rb;
-  rb.To(kRemoteSsrc);
-
-  SenderReport sr;
-  sr.From(kSenderSsrc);
-  EXPECT_TRUE(sr.WithReportBlock(rb));
-
-  rtc::scoped_ptr<RawPacket> packet(sr.Build());
-  RtcpPacketParser parser;
-  parser.Parse(packet->Buffer(), packet->Length());
-  EXPECT_EQ(1, parser.sender_report()->num_packets());
-  EXPECT_EQ(kSenderSsrc, parser.sender_report()->Ssrc());
-  EXPECT_EQ(1, parser.report_block()->num_packets());
-  EXPECT_EQ(kRemoteSsrc, parser.report_block()->Ssrc());
-}
-
-TEST(RtcpPacketTest, SrWithTwoReportBlocks) {
-  ReportBlock rb1;
-  rb1.To(kRemoteSsrc);
-  ReportBlock rb2;
-  rb2.To(kRemoteSsrc + 1);
-
-  SenderReport sr;
-  sr.From(kSenderSsrc);
-  EXPECT_TRUE(sr.WithReportBlock(rb1));
-  EXPECT_TRUE(sr.WithReportBlock(rb2));
-
-  rtc::scoped_ptr<RawPacket> packet(sr.Build());
-  RtcpPacketParser parser;
-  parser.Parse(packet->Buffer(), packet->Length());
-  EXPECT_EQ(1, parser.sender_report()->num_packets());
-  EXPECT_EQ(kSenderSsrc, parser.sender_report()->Ssrc());
-  EXPECT_EQ(2, parser.report_block()->num_packets());
-  EXPECT_EQ(1, parser.report_blocks_per_ssrc(kRemoteSsrc));
-  EXPECT_EQ(1, parser.report_blocks_per_ssrc(kRemoteSsrc + 1));
-}
-
-TEST(RtcpPacketTest, SrWithTooManyReportBlocks) {
-  SenderReport sr;
-  sr.From(kSenderSsrc);
-  const int kMaxReportBlocks = (1 << 5) - 1;
-  ReportBlock rb;
-  for (int i = 0; i < kMaxReportBlocks; ++i) {
-    rb.To(kRemoteSsrc + i);
-    EXPECT_TRUE(sr.WithReportBlock(rb));
-  }
-  rb.To(kRemoteSsrc + kMaxReportBlocks);
-  EXPECT_FALSE(sr.WithReportBlock(rb));
-}
-
-TEST(RtcpPacketTest, AppWithNoData) {
-  App app;
-  app.WithSubType(30);
-  uint32_t name = 'n' << 24;
-  name += 'a' << 16;
-  name += 'm' << 8;
-  name += 'e';
-  app.WithName(name);
-
-  rtc::scoped_ptr<RawPacket> packet(app.Build());
-  RtcpPacketParser parser;
-  parser.Parse(packet->Buffer(), packet->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);
-
-  rtc::scoped_ptr<RawPacket> packet(app.Build());
-  RtcpPacketParser parser;
-  parser.Parse(packet->Buffer(), packet->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, BuildWithTooSmallBuffer) {
   ReportBlock rb;
diff --git a/webrtc/modules/rtp_rtcp/source/rtcp_receiver_unittest.cc b/webrtc/modules/rtp_rtcp/source/rtcp_receiver_unittest.cc
index f36c04e..d239d85 100644
--- a/webrtc/modules/rtp_rtcp/source/rtcp_receiver_unittest.cc
+++ b/webrtc/modules/rtp_rtcp/source/rtcp_receiver_unittest.cc
@@ -29,6 +29,7 @@
 #include "webrtc/modules/rtp_rtcp/source/rtcp_packet/receiver_report.h"
 #include "webrtc/modules/rtp_rtcp/source/rtcp_packet/remb.h"
 #include "webrtc/modules/rtp_rtcp/source/rtcp_packet/sdes.h"
+#include "webrtc/modules/rtp_rtcp/source/rtcp_packet/sender_report.h"
 #include "webrtc/modules/rtp_rtcp/source/rtcp_packet/sli.h"
 #include "webrtc/modules/rtp_rtcp/source/rtcp_packet/tmmbr.h"
 #include "webrtc/modules/rtp_rtcp/source/rtcp_packet/transport_feedback.h"
diff --git a/webrtc/modules/rtp_rtcp/source/rtcp_sender.cc b/webrtc/modules/rtp_rtcp/source/rtcp_sender.cc
index 64331a5..4b0914d 100644
--- a/webrtc/modules/rtp_rtcp/source/rtcp_sender.cc
+++ b/webrtc/modules/rtp_rtcp/source/rtcp_sender.cc
@@ -33,6 +33,7 @@
 #include "webrtc/modules/rtp_rtcp/source/rtcp_packet/remb.h"
 #include "webrtc/modules/rtp_rtcp/source/rtcp_packet/rpsi.h"
 #include "webrtc/modules/rtp_rtcp/source/rtcp_packet/sdes.h"
+#include "webrtc/modules/rtp_rtcp/source/rtcp_packet/sender_report.h"
 #include "webrtc/modules/rtp_rtcp/source/rtcp_packet/sli.h"
 #include "webrtc/modules/rtp_rtcp/source/rtcp_packet/tmmbn.h"
 #include "webrtc/modules/rtp_rtcp/source/rtcp_packet/tmmbr.h"
@@ -483,8 +484,7 @@
 
   rtcp::SenderReport* report = new rtcp::SenderReport();
   report->From(ssrc_);
-  report->WithNtpSec(ctx.ntp_sec_);
-  report->WithNtpFrac(ctx.ntp_frac_);
+  report->WithNtp(NtpTime(ctx.ntp_sec_, ctx.ntp_frac_));
   report->WithRtpTimestamp(rtp_timestamp);
   report->WithPacketCount(ctx.feedback_state_.packets_sent);
   report->WithOctetCount(ctx.feedback_state_.media_bytes_sent);
diff --git a/webrtc/modules/rtp_rtcp/source/rtcp_sender.h b/webrtc/modules/rtp_rtcp/source/rtcp_sender.h
index dd3aec4..3cc8f4a 100644
--- a/webrtc/modules/rtp_rtcp/source/rtcp_sender.h
+++ b/webrtc/modules/rtp_rtcp/source/rtcp_sender.h
@@ -25,6 +25,7 @@
 #include "webrtc/modules/rtp_rtcp/include/receive_statistics.h"
 #include "webrtc/modules/rtp_rtcp/include/rtp_rtcp_defines.h"
 #include "webrtc/modules/rtp_rtcp/source/rtcp_packet.h"
+#include "webrtc/modules/rtp_rtcp/source/rtcp_packet/report_block.h"
 #include "webrtc/modules/rtp_rtcp/source/rtcp_utility.h"
 #include "webrtc/modules/rtp_rtcp/source/rtp_utility.h"
 #include "webrtc/modules/rtp_rtcp/source/tmmbr_help.h"