RTCP Bye packet moved to own file
 Bye class got support for Parsing
 Reason field implemented

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

Cr-Original-Commit-Position: refs/heads/master@{#10741}
Cr-Mirrored-From: https://chromium.googlesource.com/external/webrtc
Cr-Mirrored-Commit: 50c5136cb2ad11eb9ba3df1a1d54d527c8a0dc77
diff --git a/modules/modules.gyp b/modules/modules.gyp
index 44cf73e..0c981e6 100644
--- a/modules/modules.gyp
+++ b/modules/modules.gyp
@@ -305,6 +305,7 @@
                 'rtp_rtcp/source/rtcp_format_remb_unittest.cc',
                 'rtp_rtcp/source/rtcp_packet_unittest.cc',
                 'rtp_rtcp/source/rtcp_packet/app_unittest.cc',
+                'rtp_rtcp/source/rtcp_packet/bye_unittest.cc',
                 'rtp_rtcp/source/rtcp_packet/extended_jitter_report_unittest.cc',
                 'rtp_rtcp/source/rtcp_packet/report_block_unittest.cc',
                 'rtp_rtcp/source/rtcp_packet/transport_feedback_unittest.cc',
diff --git a/modules/rtp_rtcp/BUILD.gn b/modules/rtp_rtcp/BUILD.gn
index f7d887d..03b72ad 100644
--- a/modules/rtp_rtcp/BUILD.gn
+++ b/modules/rtp_rtcp/BUILD.gn
@@ -48,6 +48,8 @@
     "source/rtcp_packet.h",
     "source/rtcp_packet/app.cc",
     "source/rtcp_packet/app.h",
+    "source/rtcp_packet/bye.cc",
+    "source/rtcp_packet/bye.h",
     "source/rtcp_packet/extended_jitter_report.cc",
     "source/rtcp_packet/extended_jitter_report.h",
     "source/rtcp_packet/report_block.cc",
diff --git a/modules/rtp_rtcp/rtp_rtcp.gypi b/modules/rtp_rtcp/rtp_rtcp.gypi
index 71e2ce7..eaa5b15 100644
--- a/modules/rtp_rtcp/rtp_rtcp.gypi
+++ b/modules/rtp_rtcp/rtp_rtcp.gypi
@@ -43,6 +43,8 @@
         'source/rtcp_packet.h',
         'source/rtcp_packet/app.cc',
         'source/rtcp_packet/app.h',
+        'source/rtcp_packet/bye.cc',
+        'source/rtcp_packet/bye.h',
         'source/rtcp_packet/extended_jitter_report.cc',
         'source/rtcp_packet/extended_jitter_report.h',
         'source/rtcp_packet/report_block.cc',
diff --git a/modules/rtp_rtcp/source/rtcp_packet.cc b/modules/rtp_rtcp/source/rtcp_packet.cc
index be03d9b..e330518 100644
--- a/modules/rtp_rtcp/source/rtcp_packet.cc
+++ b/modules/rtp_rtcp/source/rtcp_packet.cc
@@ -19,7 +19,6 @@
 using webrtc::RTCPUtility::kBtVoipMetric;
 
 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;
@@ -29,7 +28,6 @@
 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;
@@ -205,28 +203,6 @@
   }
 }
 
-// Bye packet (BYE) (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|    SC   |   PT=BYE=203  |             length            |
-//       +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
-//       |                           SSRC/CSRC                           |
-//       +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
-//       :                              ...                              :
-//       +=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+
-// (opt) |     length    |               reason for leaving            ...
-//       +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
-
-void CreateBye(const RTCPPacketBYE& bye,
-               const std::vector<uint32_t>& csrcs,
-               uint8_t* buffer,
-               size_t* pos) {
-  AssignUWord32(buffer, pos, bye.SenderSSRC);
-  for (uint32_t csrc : csrcs)
-    AssignUWord32(buffer, pos, csrc);
-}
-
 // RFC 4585: Feedback format.
 //
 // Common packet format:
@@ -801,29 +777,6 @@
   return length;
 }
 
-bool Bye::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;
-  }
-  size_t length = HeaderLength();
-  CreateHeader(length, PT_BYE, length, packet, index);
-  CreateBye(bye_, csrcs_, packet, index);
-  return true;
-}
-
-bool Bye::WithCsrc(uint32_t csrc) {
-  if (csrcs_.size() >= kMaxNumberOfCsrcs) {
-    LOG(LS_WARNING) << "Max CSRC size reached.";
-    return false;
-  }
-  csrcs_.push_back(csrc);
-  return true;
-}
-
 bool Pli::Create(uint8_t* packet,
                  size_t* index,
                  size_t max_length,
diff --git a/modules/rtp_rtcp/source/rtcp_packet.h b/modules/rtp_rtcp/source/rtcp_packet.h
index bea8307..3ac6618 100644
--- a/modules/rtp_rtcp/source/rtcp_packet.h
+++ b/modules/rtp_rtcp/source/rtcp_packet.h
@@ -319,56 +319,6 @@
   RTC_DISALLOW_COPY_AND_ASSIGN(Sdes);
 };
 
-//
-// Bye packet (BYE) (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|    SC   |   PT=BYE=203  |             length            |
-//       +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
-//       |                           SSRC/CSRC                           |
-//       +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
-//       :                              ...                              :
-//       +=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+
-// (opt) |     length    |               reason for leaving            ...
-//       +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
-
-class Bye : public RtcpPacket {
- public:
-  Bye() : RtcpPacket() {
-    memset(&bye_, 0, sizeof(bye_));
-  }
-
-  virtual ~Bye() {}
-
-  void From(uint32_t ssrc) {
-    bye_.SenderSSRC = ssrc;
-  }
-
-  bool WithCsrc(uint32_t csrc);
-
-  // TODO(sprang): Add support for reason field?
-
- protected:
-  bool Create(uint8_t* packet,
-              size_t* index,
-              size_t max_length,
-              RtcpPacket::PacketReadyCallback* callback) const override;
-
- private:
-  static const int kMaxNumberOfCsrcs = 0x1f - 1;  // First item is sender SSRC.
-
-  size_t BlockLength() const {
-    size_t source_count = 1 + csrcs_.size();
-    return kHeaderLength + 4 * source_count;
-  }
-
-  RTCPUtility::RTCPPacketBYE bye_;
-  std::vector<uint32_t> csrcs_;
-
-  RTC_DISALLOW_COPY_AND_ASSIGN(Bye);
-};
-
 // RFC 4585: Feedback format.
 //
 // Common packet format:
diff --git a/modules/rtp_rtcp/source/rtcp_packet/bye.cc b/modules/rtp_rtcp/source/rtcp_packet/bye.cc
new file mode 100644
index 0000000..4cfc921
--- /dev/null
+++ b/modules/rtp_rtcp/source/rtcp_packet/bye.cc
@@ -0,0 +1,133 @@
+/*
+ *  Copyright (c) 2015 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/bye.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 {
+
+// Bye packet (BYE) (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|    SC   |   PT=BYE=203  |             length            |
+//       +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+//       |                           SSRC/CSRC                           |
+//       +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+//       :                              ...                              :
+//       +=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+
+// (opt) |     length    |               reason for leaving            ...
+//       +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+Bye::Bye() : sender_ssrc_(0) {}
+
+bool Bye::Parse(const RtcpCommonHeader& header, const uint8_t* payload) {
+  RTC_DCHECK(header.packet_type == kPacketType);
+
+  const uint8_t src_count = header.count_or_format;
+  // Validate packet.
+  if (header.payload_size_bytes < 4u * src_count) {
+    LOG(LS_WARNING)
+        << "Packet is too small to contain CSRCs it promise to have.";
+    return false;
+  }
+  bool has_reason = (header.payload_size_bytes > 4u * src_count);
+  uint8_t reason_length = 0;
+  if (has_reason) {
+    reason_length = payload[4u * src_count];
+    if (header.payload_size_bytes - 4u * src_count < 1u + reason_length) {
+      LOG(LS_WARNING) << "Invalid reason length: " << reason_length;
+      return false;
+    }
+  }
+  // Once sure packet is valid, copy values.
+  if (src_count == 0) {  // A count value of zero is valid, but useless.
+    sender_ssrc_ = 0;
+    csrcs_.clear();
+  } else {
+    sender_ssrc_ = ByteReader<uint32_t>::ReadBigEndian(payload);
+    csrcs_.resize(src_count - 1);
+    for (size_t i = 1; i < src_count; ++i)
+      csrcs_[i - 1] = ByteReader<uint32_t>::ReadBigEndian(&payload[4 * i]);
+  }
+
+  if (has_reason) {
+    reason_.assign(reinterpret_cast<const char*>(&payload[4u * src_count + 1]),
+                   reason_length);
+  } else {
+    reason_.clear();
+  }
+
+  return true;
+}
+
+bool Bye::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(1 + csrcs_.size(), kPacketType, HeaderLength(), packet, index);
+  // Store srcs of the leaving clients.
+  ByteWriter<uint32_t>::WriteBigEndian(&packet[*index], sender_ssrc_);
+  *index += sizeof(uint32_t);
+  for (uint32_t csrc : csrcs_) {
+    ByteWriter<uint32_t>::WriteBigEndian(&packet[*index], csrc);
+    *index += sizeof(uint32_t);
+  }
+  // Store the reason to leave.
+  if (!reason_.empty()) {
+    uint8_t reason_length = reason_.size();
+    packet[(*index)++] = reason_length;
+    memcpy(&packet[*index], reason_.data(), reason_length);
+    *index += reason_length;
+    // Add padding bytes if needed.
+    size_t bytes_to_pad = index_end - *index;
+    RTC_DCHECK_LE(bytes_to_pad, 3u);
+    if (bytes_to_pad > 0) {
+      memset(&packet[*index], 0, bytes_to_pad);
+      *index += bytes_to_pad;
+    }
+  }
+  RTC_DCHECK_EQ(index_end, *index);
+  return true;
+}
+
+bool Bye::WithCsrc(uint32_t csrc) {
+  if (csrcs_.size() >= kMaxNumberOfCsrcs) {
+    LOG(LS_WARNING) << "Max CSRC size reached.";
+    return false;
+  }
+  csrcs_.push_back(csrc);
+  return true;
+}
+
+void Bye::WithReason(const std::string& reason) {
+  RTC_DCHECK_LE(reason.size(), 0xffu);
+  reason_ = reason;
+}
+
+size_t Bye::BlockLength() const {
+  size_t src_count = (1 + csrcs_.size());
+  size_t reason_size_in_32bits = reason_.empty() ? 0 : (reason_.size() / 4 + 1);
+  return kHeaderLength + 4 * (src_count + reason_size_in_32bits);
+}
+
+}  // namespace rtcp
+}  // namespace webrtc
diff --git a/modules/rtp_rtcp/source/rtcp_packet/bye.h b/modules/rtp_rtcp/source/rtcp_packet/bye.h
new file mode 100644
index 0000000..6b4a181
--- /dev/null
+++ b/modules/rtp_rtcp/source/rtcp_packet/bye.h
@@ -0,0 +1,63 @@
+/*
+ *  Copyright (c) 2015 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_BYE_H_
+#define WEBRTC_MODULES_RTP_RTCP_SOURCE_RTCP_PACKET_BYE_H_
+
+#include <string>
+#include <vector>
+
+#include "webrtc/modules/rtp_rtcp/source/rtcp_packet.h"
+#include "webrtc/modules/rtp_rtcp/source/rtcp_utility.h"
+
+namespace webrtc {
+namespace rtcp {
+
+class Bye : public RtcpPacket {
+ public:
+  static const uint8_t kPacketType = 203;
+
+  Bye();
+  virtual ~Bye() {}
+
+  // 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; }
+  bool WithCsrc(uint32_t csrc);
+  void WithReason(const std::string& reason);
+
+  uint32_t sender_ssrc() const { return sender_ssrc_; }
+  const std::vector<uint32_t>& csrcs() const { return csrcs_; }
+  const std::string& reason() const { return reason_; }
+
+ protected:
+  bool Create(uint8_t* packet,
+              size_t* index,
+              size_t max_length,
+              RtcpPacket::PacketReadyCallback* callback) const override;
+
+ private:
+  static const int kMaxNumberOfCsrcs = 0x1f - 1;  // First item is sender SSRC.
+
+  size_t BlockLength() const override;
+
+  uint32_t sender_ssrc_;
+  std::vector<uint32_t> csrcs_;
+  std::string reason_;
+
+  RTC_DISALLOW_COPY_AND_ASSIGN(Bye);
+};
+
+}  // namespace rtcp
+}  // namespace webrtc
+#endif  // WEBRTC_MODULES_RTP_RTCP_SOURCE_RTCP_PACKET_BYE_H_
diff --git a/modules/rtp_rtcp/source/rtcp_packet/bye_unittest.cc b/modules/rtp_rtcp/source/rtcp_packet/bye_unittest.cc
new file mode 100644
index 0000000..0728ed9
--- /dev/null
+++ b/modules/rtp_rtcp/source/rtcp_packet/bye_unittest.cc
@@ -0,0 +1,173 @@
+/*
+ *  Copyright (c) 2015 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/bye.h"
+
+#include "testing/gmock/include/gmock/gmock.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#include "webrtc/modules/rtp_rtcp/source/rtcp_utility.h"
+
+using ::testing::ElementsAre;
+
+using webrtc::rtcp::Bye;
+using webrtc::rtcp::RawPacket;
+using webrtc::RTCPUtility::RtcpCommonHeader;
+using webrtc::RTCPUtility::RtcpParseCommonHeader;
+
+namespace webrtc {
+namespace {
+
+const uint32_t kSenderSsrc = 0x12345678;
+const uint32_t kCsrc1 = 0x22232425;
+const uint32_t kCsrc2 = 0x33343536;
+
+class RtcpPacketByeTest : public ::testing::Test {
+ protected:
+  void BuildPacket() { packet = bye.Build().Pass(); }
+  void ParsePacket() {
+    RtcpCommonHeader header;
+    EXPECT_TRUE(
+        RtcpParseCommonHeader(packet->Buffer(), packet->Length(), &header));
+    // Check that there is exactly one RTCP packet in the buffer.
+    EXPECT_EQ(header.BlockSize(), packet->Length());
+    EXPECT_TRUE(parsed_bye.Parse(
+        header, packet->Buffer() + RtcpCommonHeader::kHeaderSizeBytes));
+  }
+
+  Bye bye;
+  rtc::scoped_ptr<RawPacket> packet;
+  Bye parsed_bye;
+};
+
+TEST_F(RtcpPacketByeTest, Bye) {
+  bye.From(kSenderSsrc);
+
+  BuildPacket();
+  ParsePacket();
+
+  EXPECT_EQ(kSenderSsrc, parsed_bye.sender_ssrc());
+  EXPECT_TRUE(parsed_bye.csrcs().empty());
+  EXPECT_TRUE(parsed_bye.reason().empty());
+}
+
+TEST_F(RtcpPacketByeTest, WithCsrcs) {
+  bye.From(kSenderSsrc);
+  EXPECT_TRUE(bye.WithCsrc(kCsrc1));
+  EXPECT_TRUE(bye.WithCsrc(kCsrc2));
+  EXPECT_TRUE(bye.reason().empty());
+
+  BuildPacket();
+  EXPECT_EQ(16u, packet->Length());  // Header: 4, 3xSRCs: 12, Reason: 0.
+
+  ParsePacket();
+
+  EXPECT_EQ(kSenderSsrc, parsed_bye.sender_ssrc());
+  EXPECT_THAT(parsed_bye.csrcs(), ElementsAre(kCsrc1, kCsrc2));
+  EXPECT_TRUE(parsed_bye.reason().empty());
+}
+
+TEST_F(RtcpPacketByeTest, WithCsrcsAndReason) {
+  const std::string kReason = "Some Reason";
+
+  bye.From(kSenderSsrc);
+  EXPECT_TRUE(bye.WithCsrc(kCsrc1));
+  EXPECT_TRUE(bye.WithCsrc(kCsrc2));
+  bye.WithReason(kReason);
+
+  BuildPacket();
+  EXPECT_EQ(28u, packet->Length());  // Header: 4, 3xSRCs: 12, Reason: 12.
+
+  ParsePacket();
+
+  EXPECT_EQ(kSenderSsrc, parsed_bye.sender_ssrc());
+  EXPECT_THAT(parsed_bye.csrcs(), ElementsAre(kCsrc1, kCsrc2));
+  EXPECT_EQ(kReason, parsed_bye.reason());
+}
+
+TEST_F(RtcpPacketByeTest, WithTooManyCsrcs) {
+  bye.From(kSenderSsrc);
+  const int kMaxCsrcs = (1 << 5) - 2;  // 5 bit len, first item is sender SSRC.
+  for (int i = 0; i < kMaxCsrcs; ++i) {
+    EXPECT_TRUE(bye.WithCsrc(i));
+  }
+  EXPECT_FALSE(bye.WithCsrc(kMaxCsrcs));
+}
+
+TEST_F(RtcpPacketByeTest, WithAReason) {
+  const std::string kReason = "Some Random Reason";
+
+  bye.From(kSenderSsrc);
+  bye.WithReason(kReason);
+
+  BuildPacket();
+  ParsePacket();
+
+  EXPECT_EQ(kSenderSsrc, parsed_bye.sender_ssrc());
+  EXPECT_TRUE(parsed_bye.csrcs().empty());
+  EXPECT_EQ(kReason, parsed_bye.reason());
+}
+
+TEST_F(RtcpPacketByeTest, WithReasons) {
+  // Test that packet creation/parsing behave with reasons of different length
+  // both when it require padding and when it does not.
+  for (size_t reminder = 0; reminder < 4; ++reminder) {
+    const std::string kReason(4 + reminder, 'a' + reminder);
+    bye.From(kSenderSsrc);
+    bye.WithReason(kReason);
+
+    BuildPacket();
+    ParsePacket();
+
+    EXPECT_EQ(kReason, parsed_bye.reason());
+  }
+}
+
+TEST_F(RtcpPacketByeTest, ParseEmptyPacket) {
+  RtcpCommonHeader header;
+  header.packet_type = Bye::kPacketType;
+  header.count_or_format = 0;
+  header.payload_size_bytes = 0;
+  uint8_t empty_payload[1];
+
+  EXPECT_TRUE(parsed_bye.Parse(header, empty_payload + 1));
+  EXPECT_EQ(0u, parsed_bye.sender_ssrc());
+  EXPECT_TRUE(parsed_bye.csrcs().empty());
+  EXPECT_TRUE(parsed_bye.reason().empty());
+}
+
+TEST_F(RtcpPacketByeTest, ParseFailOnInvalidSrcCount) {
+  bye.From(kSenderSsrc);
+
+  BuildPacket();
+
+  RtcpCommonHeader header;
+  RtcpParseCommonHeader(packet->Buffer(), packet->Length(), &header);
+  header.count_or_format = 2;  // Lie there are 2 ssrcs, not one.
+
+  EXPECT_FALSE(parsed_bye.Parse(
+      header, packet->Buffer() + RtcpCommonHeader::kHeaderSizeBytes));
+}
+
+TEST_F(RtcpPacketByeTest, ParseFailOnInvalidReasonLength) {
+  bye.From(kSenderSsrc);
+  bye.WithReason("18 characters long");
+
+  BuildPacket();
+
+  RtcpCommonHeader header;
+  RtcpParseCommonHeader(packet->Buffer(), packet->Length(), &header);
+  header.payload_size_bytes -= 4;  // Payload is usually 32bit aligned.
+
+  EXPECT_FALSE(parsed_bye.Parse(
+      header, packet->Buffer() + RtcpCommonHeader::kHeaderSizeBytes));
+}
+
+}  // namespace
+}  // namespace webrtc
diff --git a/modules/rtp_rtcp/source/rtcp_packet_unittest.cc b/modules/rtp_rtcp/source/rtcp_packet_unittest.cc
index 4c1d55e..3cf3fea 100644
--- a/modules/rtp_rtcp/source/rtcp_packet_unittest.cc
+++ b/modules/rtp_rtcp/source/rtcp_packet_unittest.cc
@@ -15,6 +15,7 @@
 
 #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/test/rtcp_packet_parser.h"
 
 using ::testing::ElementsAre;
@@ -571,43 +572,6 @@
   EXPECT_EQ(1, parser.fir()->num_packets());
 }
 
-TEST(RtcpPacketTest, Bye) {
-  Bye bye;
-  bye.From(kSenderSsrc);
-
-  rtc::scoped_ptr<RawPacket> packet(bye.Build());
-  RtcpPacketParser parser;
-  parser.Parse(packet->Buffer(), packet->Length());
-  EXPECT_EQ(1, parser.bye()->num_packets());
-  EXPECT_EQ(kSenderSsrc, parser.bye()->Ssrc());
-}
-
-TEST(RtcpPacketTest, ByeWithCsrcs) {
-  Fir fir;
-  Bye bye;
-  bye.From(kSenderSsrc);
-  EXPECT_TRUE(bye.WithCsrc(0x22222222));
-  EXPECT_TRUE(bye.WithCsrc(0x33333333));
-  bye.Append(&fir);
-
-  rtc::scoped_ptr<RawPacket> packet(bye.Build());
-  RtcpPacketParser parser;
-  parser.Parse(packet->Buffer(), packet->Length());
-  EXPECT_EQ(1, parser.bye()->num_packets());
-  EXPECT_EQ(kSenderSsrc, parser.bye()->Ssrc());
-  EXPECT_EQ(1, parser.fir()->num_packets());
-}
-
-TEST(RtcpPacketTest, ByeWithTooManyCsrcs) {
-  Bye bye;
-  bye.From(kSenderSsrc);
-  const int kMaxCsrcs = (1 << 5) - 2;  // 5 bit len, first item is sender SSRC.
-  for (int i = 0; i < kMaxCsrcs; ++i) {
-    EXPECT_TRUE(bye.WithCsrc(i));
-  }
-  EXPECT_FALSE(bye.WithCsrc(kMaxCsrcs));
-}
-
 TEST(RtcpPacketTest, BuildWithInputBuffer) {
   Fir fir;
   ReportBlock rb;
diff --git a/modules/rtp_rtcp/source/rtcp_receiver_unittest.cc b/modules/rtp_rtcp/source/rtcp_receiver_unittest.cc
index 53c3177..5b0e656 100644
--- a/modules/rtp_rtcp/source/rtcp_receiver_unittest.cc
+++ b/modules/rtp_rtcp/source/rtcp_receiver_unittest.cc
@@ -26,6 +26,7 @@
 #include "webrtc/modules/rtp_rtcp/source/rtp_rtcp_impl.h"
 #include "webrtc/modules/rtp_rtcp/source/rtp_utility.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/extended_jitter_report.h"
 #include "webrtc/modules/rtp_rtcp/source/rtcp_packet/transport_feedback.h"
 
diff --git a/modules/rtp_rtcp/source/rtcp_sender.cc b/modules/rtp_rtcp/source/rtcp_sender.cc
index ffab90e..9929299 100644
--- a/modules/rtp_rtcp/source/rtcp_sender.cc
+++ b/modules/rtp_rtcp/source/rtcp_sender.cc
@@ -23,6 +23,7 @@
 #include "webrtc/common_types.h"
 #include "webrtc/modules/rtp_rtcp/source/byte_io.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/transport_feedback.h"
 #include "webrtc/modules/rtp_rtcp/source/rtp_rtcp_impl.h"
 #include "webrtc/system_wrappers/include/critical_section_wrapper.h"