[rtp_rtcp] rtcp::Sdes moved into own file
Cleaning/Parsing will be done in the https://codereview.webrtc.org/1439553003/

BUG=webrtc:5260
R=asapersson@webrtc.org, åsapersson

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

Cr-Commit-Position: refs/heads/master@{#11274}
diff --git a/webrtc/modules/modules.gyp b/webrtc/modules/modules.gyp
index 9ca0587..37d4304 100644
--- a/webrtc/modules/modules.gyp
+++ b/webrtc/modules/modules.gyp
@@ -319,6 +319,7 @@
                 'rtp_rtcp/source/rtcp_packet/report_block_unittest.cc',
                 '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/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 0e8f07e..42de871 100644
--- a/webrtc/modules/rtp_rtcp/BUILD.gn
+++ b/webrtc/modules/rtp_rtcp/BUILD.gn
@@ -78,6 +78,8 @@
     "source/rtcp_packet/rrtr.h",
     "source/rtcp_packet/rtpfb.cc",
     "source/rtcp_packet/rtpfb.h",
+    "source/rtcp_packet/sdes.cc",
+    "source/rtcp_packet/sdes.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 0e9071b..1db0441 100644
--- a/webrtc/modules/rtp_rtcp/rtp_rtcp.gypi
+++ b/webrtc/modules/rtp_rtcp/rtp_rtcp.gypi
@@ -73,6 +73,8 @@
         'source/rtcp_packet/rrtr.h',
         'source/rtcp_packet/rtpfb.cc',
         'source/rtcp_packet/rtpfb.h',
+        'source/rtcp_packet/sdes.cc',
+        'source/rtcp_packet/sdes.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 aa7a286..ec87ed6 100644
--- a/webrtc/modules/rtp_rtcp/source/rtcp_packet.cc
+++ b/webrtc/modules/rtp_rtcp/source/rtcp_packet.cc
@@ -19,7 +19,6 @@
 using webrtc::RTCPUtility::PT_APP;
 using webrtc::RTCPUtility::PT_IJ;
 using webrtc::RTCPUtility::PT_RTPFB;
-using webrtc::RTCPUtility::PT_SDES;
 using webrtc::RTCPUtility::PT_SR;
 
 using webrtc::RTCPUtility::RTCPPacketAPP;
@@ -98,48 +97,6 @@
     *pos += ReportBlock::kLength;
   }
 }
-
-// Source Description (SDES) (RFC 3550).
-//
-//         0                   1                   2                   3
-//         0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
-//        +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
-// header |V=2|P|    SC   |  PT=SDES=202  |             length            |
-//        +=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+
-// chunk  |                          SSRC/CSRC_1                          |
-//   1    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
-//        |                           SDES items                          |
-//        |                              ...                              |
-//        +=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+
-// chunk  |                          SSRC/CSRC_2                          |
-//   2    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
-//        |                           SDES items                          |
-//        |                              ...                              |
-//        +=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+
-//
-// Canonical End-Point Identifier SDES Item (CNAME)
-//
-//    0                   1                   2                   3
-//    0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
-//   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
-//   |    CNAME=1    |     length    | user and domain name        ...
-//   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
-
-void CreateSdes(const std::vector<Sdes::Chunk>& chunks,
-                uint8_t* buffer,
-                size_t* pos) {
-  const uint8_t kSdesItemType = 1;
-  for (std::vector<Sdes::Chunk>::const_iterator it = chunks.begin();
-       it != chunks.end(); ++it) {
-    AssignUWord32(buffer, pos, (*it).ssrc);
-    AssignUWord8(buffer, pos, kSdesItemType);
-    AssignUWord8(buffer, pos, (*it).name.length());
-    memcpy(buffer + *pos, (*it).name.data(), (*it).name.length());
-    *pos += (*it).name.length();
-    memset(buffer + *pos, 0, (*it).null_octets);
-    *pos += (*it).null_octets;
-  }
-}
 }  // namespace
 
 void RtcpPacket::Append(RtcpPacket* packet) {
@@ -262,49 +219,6 @@
   return true;
 }
 
-bool Sdes::Create(uint8_t* packet,
-                  size_t* index,
-                  size_t max_length,
-                  RtcpPacket::PacketReadyCallback* callback) const {
-  assert(!chunks_.empty());
-  while (*index + BlockLength() > max_length) {
-    if (!OnBufferFull(packet, index, callback))
-      return false;
-  }
-  CreateHeader(chunks_.size(), PT_SDES, HeaderLength(), packet, index);
-  CreateSdes(chunks_, packet, index);
-  return true;
-}
-
-bool Sdes::WithCName(uint32_t ssrc, const std::string& cname) {
-  assert(cname.length() <= 0xff);
-  if (chunks_.size() >= kMaxNumberOfChunks) {
-    LOG(LS_WARNING) << "Max SDES chunks reached.";
-    return false;
-  }
-  // In each chunk, the list of items must be terminated by one or more null
-  // octets. The next chunk must start on a 32-bit boundary.
-  // CNAME (1 byte) | length (1 byte) | name | padding.
-  int null_octets = 4 - ((2 + cname.length()) % 4);
-  Chunk chunk;
-  chunk.ssrc = ssrc;
-  chunk.name = cname;
-  chunk.null_octets = null_octets;
-  chunks_.push_back(chunk);
-  return true;
-}
-
-size_t Sdes::BlockLength() const {
-  // Header (4 bytes).
-  // Chunk:
-  // SSRC/CSRC (4 bytes) | CNAME (1 byte) | length (1 byte) | name | padding.
-  size_t length = kHeaderLength;
-  for (const Chunk& chunk : chunks_)
-    length += 6 + chunk.name.length() + chunk.null_octets;
-  assert(length % 4 == 0);
-  return length;
-}
-
 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 9184ba8..2cf9005 100644
--- a/webrtc/modules/rtp_rtcp/source/rtcp_packet.h
+++ b/webrtc/modules/rtp_rtcp/source/rtcp_packet.h
@@ -12,7 +12,6 @@
 #ifndef WEBRTC_MODULES_RTP_RTCP_SOURCE_RTCP_PACKET_H_
 #define WEBRTC_MODULES_RTP_RTCP_SOURCE_RTCP_PACKET_H_
 
-#include <string>
 #include <vector>
 
 #include "webrtc/base/scoped_ptr.h"
@@ -194,62 +193,6 @@
   RTC_DISALLOW_COPY_AND_ASSIGN(SenderReport);
 };
 
-// Source Description (SDES) (RFC 3550).
-//
-//         0                   1                   2                   3
-//         0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
-//        +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
-// header |V=2|P|    SC   |  PT=SDES=202  |             length            |
-//        +=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+
-// chunk  |                          SSRC/CSRC_1                          |
-//   1    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
-//        |                           SDES items                          |
-//        |                              ...                              |
-//        +=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+
-// chunk  |                          SSRC/CSRC_2                          |
-//   2    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
-//        |                           SDES items                          |
-//        |                              ...                              |
-//        +=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+
-//
-// Canonical End-Point Identifier SDES Item (CNAME)
-//
-//    0                   1                   2                   3
-//    0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
-//   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
-//   |    CNAME=1    |     length    | user and domain name        ...
-//   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
-
-class Sdes : public RtcpPacket {
- public:
-  Sdes() : RtcpPacket() {}
-
-  virtual ~Sdes() {}
-
-  bool WithCName(uint32_t ssrc, const std::string& cname);
-
-  struct Chunk {
-    uint32_t ssrc;
-    std::string name;
-    int null_octets;
-  };
-
- protected:
-  bool Create(uint8_t* packet,
-              size_t* index,
-              size_t max_length,
-              RtcpPacket::PacketReadyCallback* callback) const override;
-
- private:
-  static const int kMaxNumberOfChunks = 0x1f;
-
-  size_t BlockLength() const;
-
-  std::vector<Chunk> chunks_;
-
-  RTC_DISALLOW_COPY_AND_ASSIGN(Sdes);
-};
-
 // Class holding a RTCP packet.
 //
 // Takes a built rtcp packet.
diff --git a/webrtc/modules/rtp_rtcp/source/rtcp_packet/sdes.cc b/webrtc/modules/rtp_rtcp/source/rtcp_packet/sdes.cc
new file mode 100644
index 0000000..38c4ef3
--- /dev/null
+++ b/webrtc/modules/rtp_rtcp/source/rtcp_packet/sdes.cc
@@ -0,0 +1,114 @@
+/*
+ *  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/sdes.h"
+
+#include "webrtc/base/logging.h"
+#include "webrtc/modules/rtp_rtcp/source/byte_io.h"
+
+using webrtc::RTCPUtility::PT_SDES;
+
+namespace webrtc {
+namespace rtcp {
+namespace {
+void AssignUWord8(uint8_t* buffer, size_t* offset, uint8_t value) {
+  buffer[(*offset)++] = value;
+}
+
+void AssignUWord32(uint8_t* buffer, size_t* offset, uint32_t value) {
+  ByteWriter<uint32_t>::WriteBigEndian(buffer + *offset, value);
+  *offset += 4;
+}
+// Source Description (SDES) (RFC 3550).
+//
+//         0                   1                   2                   3
+//         0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+//        +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+// header |V=2|P|    SC   |  PT=SDES=202  |             length            |
+//        +=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+
+// chunk  |                          SSRC/CSRC_1                          |
+//   1    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+//        |                           SDES items                          |
+//        |                              ...                              |
+//        +=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+
+// chunk  |                          SSRC/CSRC_2                          |
+//   2    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+//        |                           SDES items                          |
+//        |                              ...                              |
+//        +=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+
+//
+// Canonical End-Point Identifier SDES Item (CNAME)
+//
+//    0                   1                   2                   3
+//    0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+//   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+//   |    CNAME=1    |     length    | user and domain name        ...
+//   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+void CreateSdes(const std::vector<Sdes::Chunk>& chunks,
+                uint8_t* buffer,
+                size_t* pos) {
+  const uint8_t kSdesItemType = 1;
+  for (std::vector<Sdes::Chunk>::const_iterator it = chunks.begin();
+       it != chunks.end(); ++it) {
+    AssignUWord32(buffer, pos, (*it).ssrc);
+    AssignUWord8(buffer, pos, kSdesItemType);
+    AssignUWord8(buffer, pos, (*it).name.length());
+    memcpy(buffer + *pos, (*it).name.data(), (*it).name.length());
+    *pos += (*it).name.length();
+    memset(buffer + *pos, 0, (*it).null_octets);
+    *pos += (*it).null_octets;
+  }
+}
+}  // namespace
+
+bool Sdes::Create(uint8_t* packet,
+                  size_t* index,
+                  size_t max_length,
+                  RtcpPacket::PacketReadyCallback* callback) const {
+  assert(!chunks_.empty());
+  while (*index + BlockLength() > max_length) {
+    if (!OnBufferFull(packet, index, callback))
+      return false;
+  }
+  CreateHeader(chunks_.size(), PT_SDES, HeaderLength(), packet, index);
+  CreateSdes(chunks_, packet, index);
+  return true;
+}
+
+bool Sdes::WithCName(uint32_t ssrc, const std::string& cname) {
+  assert(cname.length() <= 0xff);
+  if (chunks_.size() >= kMaxNumberOfChunks) {
+    LOG(LS_WARNING) << "Max SDES chunks reached.";
+    return false;
+  }
+  // In each chunk, the list of items must be terminated by one or more null
+  // octets. The next chunk must start on a 32-bit boundary.
+  // CNAME (1 byte) | length (1 byte) | name | padding.
+  int null_octets = 4 - ((2 + cname.length()) % 4);
+  Chunk chunk;
+  chunk.ssrc = ssrc;
+  chunk.name = cname;
+  chunk.null_octets = null_octets;
+  chunks_.push_back(chunk);
+  return true;
+}
+
+size_t Sdes::BlockLength() const {
+  // Header (4 bytes).
+  // Chunk:
+  // SSRC/CSRC (4 bytes) | CNAME (1 byte) | length (1 byte) | name | padding.
+  size_t length = kHeaderLength;
+  for (const Chunk& chunk : chunks_)
+    length += 6 + chunk.name.length() + chunk.null_octets;
+  assert(length % 4 == 0);
+  return length;
+}
+}  // namespace rtcp
+}  // namespace webrtc
diff --git a/webrtc/modules/rtp_rtcp/source/rtcp_packet/sdes.h b/webrtc/modules/rtp_rtcp/source/rtcp_packet/sdes.h
new file mode 100644
index 0000000..5520e34
--- /dev/null
+++ b/webrtc/modules/rtp_rtcp/source/rtcp_packet/sdes.h
@@ -0,0 +1,56 @@
+/*
+ *  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_SDES_H_
+#define WEBRTC_MODULES_RTP_RTCP_SOURCE_RTCP_PACKET_SDES_H_
+
+#include <string>
+#include <vector>
+
+#include "webrtc/base/basictypes.h"
+#include "webrtc/modules/rtp_rtcp/source/rtcp_packet.h"
+#include "webrtc/modules/rtp_rtcp/source/rtcp_utility.h"
+
+namespace webrtc {
+namespace rtcp {
+// Source Description (SDES) (RFC 3550).
+class Sdes : public RtcpPacket {
+ public:
+  Sdes() : RtcpPacket() {}
+
+  virtual ~Sdes() {}
+
+  bool WithCName(uint32_t ssrc, const std::string& cname);
+
+  struct Chunk {
+    uint32_t ssrc;
+    std::string name;
+    int null_octets;
+  };
+
+ protected:
+  bool Create(uint8_t* packet,
+              size_t* index,
+              size_t max_length,
+              RtcpPacket::PacketReadyCallback* callback) const override;
+
+ private:
+  static const int kMaxNumberOfChunks = 0x1f;
+
+  size_t BlockLength() const;
+
+  std::vector<Chunk> chunks_;
+
+  RTC_DISALLOW_COPY_AND_ASSIGN(Sdes);
+};
+}  // namespace rtcp
+}  // namespace webrtc
+#endif  // WEBRTC_MODULES_RTP_RTCP_SOURCE_RTCP_PACKET_SDES_H_
diff --git a/webrtc/modules/rtp_rtcp/source/rtcp_packet/sdes_unittest.cc b/webrtc/modules/rtp_rtcp/source/rtcp_packet/sdes_unittest.cc
new file mode 100644
index 0000000..65f8096
--- /dev/null
+++ b/webrtc/modules/rtp_rtcp/source/rtcp_packet/sdes_unittest.cc
@@ -0,0 +1,81 @@
+/*
+ *  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/sdes.h"
+
+#include "testing/gtest/include/gtest/gtest.h"
+
+#include "webrtc/modules/rtp_rtcp/source/byte_io.h"
+#include "webrtc/test/rtcp_packet_parser.h"
+
+using webrtc::rtcp::RawPacket;
+using webrtc::rtcp::Sdes;
+using webrtc::test::RtcpPacketParser;
+
+namespace webrtc {
+const uint32_t kSenderSsrc = 0x12345678;
+
+TEST(RtcpPacketSdesTest, WithOneChunk) {
+  Sdes sdes;
+  EXPECT_TRUE(sdes.WithCName(kSenderSsrc, "alice@host"));
+
+  rtc::scoped_ptr<RawPacket> packet(sdes.Build());
+  RtcpPacketParser parser;
+  parser.Parse(packet->Buffer(), packet->Length());
+  EXPECT_EQ(1, parser.sdes()->num_packets());
+  EXPECT_EQ(1, parser.sdes_chunk()->num_packets());
+  EXPECT_EQ(kSenderSsrc, parser.sdes_chunk()->Ssrc());
+  EXPECT_EQ("alice@host", parser.sdes_chunk()->Cname());
+}
+
+TEST(RtcpPacketSdesTest, WithMultipleChunks) {
+  Sdes sdes;
+  EXPECT_TRUE(sdes.WithCName(kSenderSsrc, "a"));
+  EXPECT_TRUE(sdes.WithCName(kSenderSsrc + 1, "ab"));
+  EXPECT_TRUE(sdes.WithCName(kSenderSsrc + 2, "abc"));
+  EXPECT_TRUE(sdes.WithCName(kSenderSsrc + 3, "abcd"));
+  EXPECT_TRUE(sdes.WithCName(kSenderSsrc + 4, "abcde"));
+  EXPECT_TRUE(sdes.WithCName(kSenderSsrc + 5, "abcdef"));
+
+  rtc::scoped_ptr<RawPacket> packet(sdes.Build());
+  RtcpPacketParser parser;
+  parser.Parse(packet->Buffer(), packet->Length());
+  EXPECT_EQ(1, parser.sdes()->num_packets());
+  EXPECT_EQ(6, parser.sdes_chunk()->num_packets());
+  EXPECT_EQ(kSenderSsrc + 5, parser.sdes_chunk()->Ssrc());
+  EXPECT_EQ("abcdef", parser.sdes_chunk()->Cname());
+}
+
+TEST(RtcpPacketSdesTest, WithTooManyChunks) {
+  Sdes sdes;
+  const int kMaxChunks = (1 << 5) - 1;
+  for (int i = 0; i < kMaxChunks; ++i) {
+    uint32_t ssrc = kSenderSsrc + i;
+    std::ostringstream oss;
+    oss << "cname" << i;
+    EXPECT_TRUE(sdes.WithCName(ssrc, oss.str()));
+  }
+  EXPECT_FALSE(sdes.WithCName(kSenderSsrc + kMaxChunks, "foo"));
+}
+
+TEST(RtcpPacketSdesTest, CnameItemWithEmptyString) {
+  Sdes sdes;
+  EXPECT_TRUE(sdes.WithCName(kSenderSsrc, ""));
+
+  rtc::scoped_ptr<RawPacket> packet(sdes.Build());
+  RtcpPacketParser parser;
+  parser.Parse(packet->Buffer(), packet->Length());
+  EXPECT_EQ(1, parser.sdes()->num_packets());
+  EXPECT_EQ(1, parser.sdes_chunk()->num_packets());
+  EXPECT_EQ(kSenderSsrc, parser.sdes_chunk()->Ssrc());
+  EXPECT_EQ("", parser.sdes_chunk()->Cname());
+}
+
+}  // 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 7b94287..6b4ef90 100644
--- a/webrtc/modules/rtp_rtcp/source/rtcp_packet_unittest.cc
+++ b/webrtc/modules/rtp_rtcp/source/rtcp_packet_unittest.cc
@@ -26,7 +26,6 @@
 using webrtc::rtcp::RawPacket;
 using webrtc::rtcp::ReceiverReport;
 using webrtc::rtcp::ReportBlock;
-using webrtc::rtcp::Sdes;
 using webrtc::rtcp::SenderReport;
 using webrtc::test::RtcpPacketParser;
 
@@ -152,63 +151,6 @@
       parser.app_item()->DataLength()));
 }
 
-TEST(RtcpPacketTest, SdesWithOneChunk) {
-  Sdes sdes;
-  EXPECT_TRUE(sdes.WithCName(kSenderSsrc, "alice@host"));
-
-  rtc::scoped_ptr<RawPacket> packet(sdes.Build());
-  RtcpPacketParser parser;
-  parser.Parse(packet->Buffer(), packet->Length());
-  EXPECT_EQ(1, parser.sdes()->num_packets());
-  EXPECT_EQ(1, parser.sdes_chunk()->num_packets());
-  EXPECT_EQ(kSenderSsrc, parser.sdes_chunk()->Ssrc());
-  EXPECT_EQ("alice@host", parser.sdes_chunk()->Cname());
-}
-
-TEST(RtcpPacketTest, SdesWithMultipleChunks) {
-  Sdes sdes;
-  EXPECT_TRUE(sdes.WithCName(kSenderSsrc, "a"));
-  EXPECT_TRUE(sdes.WithCName(kSenderSsrc + 1, "ab"));
-  EXPECT_TRUE(sdes.WithCName(kSenderSsrc + 2, "abc"));
-  EXPECT_TRUE(sdes.WithCName(kSenderSsrc + 3, "abcd"));
-  EXPECT_TRUE(sdes.WithCName(kSenderSsrc + 4, "abcde"));
-  EXPECT_TRUE(sdes.WithCName(kSenderSsrc + 5, "abcdef"));
-
-  rtc::scoped_ptr<RawPacket> packet(sdes.Build());
-  RtcpPacketParser parser;
-  parser.Parse(packet->Buffer(), packet->Length());
-  EXPECT_EQ(1, parser.sdes()->num_packets());
-  EXPECT_EQ(6, parser.sdes_chunk()->num_packets());
-  EXPECT_EQ(kSenderSsrc + 5, parser.sdes_chunk()->Ssrc());
-  EXPECT_EQ("abcdef", parser.sdes_chunk()->Cname());
-}
-
-TEST(RtcpPacketTest, SdesWithTooManyChunks) {
-  Sdes sdes;
-  const int kMaxChunks = (1 << 5) - 1;
-  for (int i = 0; i < kMaxChunks; ++i) {
-    uint32_t ssrc = kSenderSsrc + i;
-    std::ostringstream oss;
-    oss << "cname" << i;
-    EXPECT_TRUE(sdes.WithCName(ssrc, oss.str()));
-  }
-  EXPECT_FALSE(sdes.WithCName(kSenderSsrc + kMaxChunks, "foo"));
-}
-
-TEST(RtcpPacketTest, CnameItemWithEmptyString) {
-  Sdes sdes;
-  EXPECT_TRUE(sdes.WithCName(kSenderSsrc, ""));
-
-  rtc::scoped_ptr<RawPacket> packet(sdes.Build());
-  RtcpPacketParser parser;
-  parser.Parse(packet->Buffer(), packet->Length());
-  EXPECT_EQ(1, parser.sdes()->num_packets());
-  EXPECT_EQ(1, parser.sdes_chunk()->num_packets());
-  EXPECT_EQ(kSenderSsrc, parser.sdes_chunk()->Ssrc());
-  EXPECT_EQ("", parser.sdes_chunk()->Cname());
-}
-
-
 TEST(RtcpPacketTest, BuildWithTooSmallBuffer) {
   ReportBlock rb;
   ReceiverReport rr;
diff --git a/webrtc/modules/rtp_rtcp/source/rtcp_receiver_unittest.cc b/webrtc/modules/rtp_rtcp/source/rtcp_receiver_unittest.cc
index d9702f4..f36c04e 100644
--- a/webrtc/modules/rtp_rtcp/source/rtcp_receiver_unittest.cc
+++ b/webrtc/modules/rtp_rtcp/source/rtcp_receiver_unittest.cc
@@ -28,6 +28,7 @@
 #include "webrtc/modules/rtp_rtcp/source/rtcp_packet/pli.h"
 #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/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 bf7d24f..64331a5 100644
--- a/webrtc/modules/rtp_rtcp/source/rtcp_sender.cc
+++ b/webrtc/modules/rtp_rtcp/source/rtcp_sender.cc
@@ -32,6 +32,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/rpsi.h"
+#include "webrtc/modules/rtp_rtcp/source/rtcp_packet/sdes.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"