aboutsummaryrefslogtreecommitdiff
path: root/webrtc/modules/rtp_rtcp/source/rtcp_packet
diff options
context:
space:
mode:
Diffstat (limited to 'webrtc/modules/rtp_rtcp/source/rtcp_packet')
-rw-r--r--webrtc/modules/rtp_rtcp/source/rtcp_packet/app.cc79
-rw-r--r--webrtc/modules/rtp_rtcp/source/rtcp_packet/app.h66
-rw-r--r--webrtc/modules/rtp_rtcp/source/rtcp_packet/app_unittest.cc81
-rw-r--r--webrtc/modules/rtp_rtcp/source/rtcp_packet/bye.cc133
-rw-r--r--webrtc/modules/rtp_rtcp/source/rtcp_packet/bye.h63
-rw-r--r--webrtc/modules/rtp_rtcp/source/rtcp_packet/bye_unittest.cc173
-rw-r--r--webrtc/modules/rtp_rtcp/source/rtcp_packet/compound_packet.cc28
-rw-r--r--webrtc/modules/rtp_rtcp/source/rtcp_packet/compound_packet.h41
-rw-r--r--webrtc/modules/rtp_rtcp/source/rtcp_packet/compound_packet_unittest.cc157
-rw-r--r--webrtc/modules/rtp_rtcp/source/rtcp_packet/dlrr.cc100
-rw-r--r--webrtc/modules/rtp_rtcp/source/rtcp_packet/dlrr.h63
-rw-r--r--webrtc/modules/rtp_rtcp/source/rtcp_packet/dlrr_unittest.cc102
-rw-r--r--webrtc/modules/rtp_rtcp/source/rtcp_packet/extended_jitter_report.cc95
-rw-r--r--webrtc/modules/rtp_rtcp/source/rtcp_packet/extended_jitter_report.h63
-rw-r--r--webrtc/modules/rtp_rtcp/source/rtcp_packet/extended_jitter_report_unittest.cc98
-rw-r--r--webrtc/modules/rtp_rtcp/source/rtcp_packet/nack.cc163
-rw-r--r--webrtc/modules/rtp_rtcp/source/rtcp_packet/nack.h63
-rw-r--r--webrtc/modules/rtp_rtcp/source/rtcp_packet/nack_unittest.cc190
-rw-r--r--webrtc/modules/rtp_rtcp/source/rtcp_packet/pli.cc70
-rw-r--r--webrtc/modules/rtp_rtcp/source/rtcp_packet/pli.h49
-rw-r--r--webrtc/modules/rtp_rtcp/source/rtcp_packet/pli_unittest.cc66
-rw-r--r--webrtc/modules/rtp_rtcp/source/rtcp_packet/psfb.cc45
-rw-r--r--webrtc/modules/rtp_rtcp/source/rtcp_packet/psfb.h48
-rw-r--r--webrtc/modules/rtp_rtcp/source/rtcp_packet/receiver_report.cc89
-rw-r--r--webrtc/modules/rtp_rtcp/source/rtcp_packet/receiver_report.h66
-rw-r--r--webrtc/modules/rtp_rtcp/source/rtcp_packet/receiver_report_unittest.cc145
-rw-r--r--webrtc/modules/rtp_rtcp/source/rtcp_packet/report_block.cc89
-rw-r--r--webrtc/modules/rtp_rtcp/source/rtcp_packet/report_block.h67
-rw-r--r--webrtc/modules/rtp_rtcp/source/rtcp_packet/report_block_unittest.cc86
-rw-r--r--webrtc/modules/rtp_rtcp/source/rtcp_packet/rrtr.cc49
-rw-r--r--webrtc/modules/rtp_rtcp/source/rtcp_packet/rrtr.h49
-rw-r--r--webrtc/modules/rtp_rtcp/source/rtcp_packet/rrtr_unittest.cc51
-rw-r--r--webrtc/modules/rtp_rtcp/source/rtcp_packet/rtpfb.cc45
-rw-r--r--webrtc/modules/rtp_rtcp/source/rtcp_packet/rtpfb.h48
-rw-r--r--webrtc/modules/rtp_rtcp/source/rtcp_packet/sli.cc108
-rw-r--r--webrtc/modules/rtp_rtcp/source/rtcp_packet/sli.h81
-rw-r--r--webrtc/modules/rtp_rtcp/source/rtcp_packet/sli_unittest.cc91
-rw-r--r--webrtc/modules/rtp_rtcp/source/rtcp_packet/tmmbn.cc119
-rw-r--r--webrtc/modules/rtp_rtcp/source/rtcp_packet/tmmbn.h60
-rw-r--r--webrtc/modules/rtp_rtcp/source/rtcp_packet/tmmbn_unittest.cc84
-rw-r--r--webrtc/modules/rtp_rtcp/source/rtcp_packet/tmmbr.cc105
-rw-r--r--webrtc/modules/rtp_rtcp/source/rtcp_packet/tmmbr.h64
-rw-r--r--webrtc/modules/rtp_rtcp/source/rtcp_packet/tmmbr_unittest.cc43
-rw-r--r--webrtc/modules/rtp_rtcp/source/rtcp_packet/transport_feedback.h2
-rw-r--r--webrtc/modules/rtp_rtcp/source/rtcp_packet/voip_metric.cc107
-rw-r--r--webrtc/modules/rtp_rtcp/source/rtcp_packet/voip_metric.h53
-rw-r--r--webrtc/modules/rtp_rtcp/source/rtcp_packet/voip_metric_unittest.cc93
47 files changed, 3829 insertions, 1 deletions
diff --git a/webrtc/modules/rtp_rtcp/source/rtcp_packet/app.cc b/webrtc/modules/rtp_rtcp/source/rtcp_packet/app.cc
new file mode 100644
index 0000000000..a1ad8d6427
--- /dev/null
+++ b/webrtc/modules/rtp_rtcp/source/rtcp_packet/app.cc
@@ -0,0 +1,79 @@
+/*
+ * 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/app.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 {
+
+// Application-Defined packet (APP) (RFC 3550).
+//
+// 0 1 2 3
+// 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+// |V=2|P| subtype | PT=APP=204 | length |
+// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+// 0 | SSRC/CSRC |
+// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+// 4 | name (ASCII) |
+// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+// 8 | application-dependent data ...
+// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+bool App::Parse(const RtcpCommonHeader& header, const uint8_t* payload) {
+ RTC_DCHECK(header.packet_type == kPacketType);
+
+ sub_type_ = header.count_or_format;
+ ssrc_ = ByteReader<uint32_t>::ReadBigEndian(&payload[0]);
+ name_ = ByteReader<uint32_t>::ReadBigEndian(&payload[4]);
+ data_.SetData(&payload[8], header.payload_size_bytes - 8);
+ return true;
+}
+
+void App::WithSubType(uint8_t subtype) {
+ RTC_DCHECK_LE(subtype, 0x1f);
+ sub_type_ = subtype;
+}
+
+void App::WithData(const uint8_t* data, size_t data_length) {
+ RTC_DCHECK(data);
+ RTC_DCHECK_EQ(0u, data_length % 4) << "Data must be 32 bits aligned.";
+ RTC_DCHECK(data_length <= kMaxDataSize) << "App data size << " << data_length
+ << "exceed maximum of "
+ << kMaxDataSize << " bytes.";
+ data_.SetData(data, data_length);
+}
+
+bool App::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(sub_type_, kPacketType, HeaderLength(), packet, index);
+
+ ByteWriter<uint32_t>::WriteBigEndian(&packet[*index + 0], ssrc_);
+ ByteWriter<uint32_t>::WriteBigEndian(&packet[*index + 4], name_);
+ memcpy(&packet[*index + 8], data_.data(), data_.size());
+ *index += (8 + data_.size());
+ RTC_DCHECK_EQ(index_end, *index);
+ return true;
+}
+
+} // namespace rtcp
+} // namespace webrtc
diff --git a/webrtc/modules/rtp_rtcp/source/rtcp_packet/app.h b/webrtc/modules/rtp_rtcp/source/rtcp_packet/app.h
new file mode 100644
index 0000000000..16bd3fc2a2
--- /dev/null
+++ b/webrtc/modules/rtp_rtcp/source/rtcp_packet/app.h
@@ -0,0 +1,66 @@
+/*
+ * 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_APP_H_
+#define WEBRTC_MODULES_RTP_RTCP_SOURCE_RTCP_PACKET_APP_H_
+
+#include "webrtc/base/buffer.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_utility.h"
+
+namespace webrtc {
+namespace rtcp {
+
+class App : public RtcpPacket {
+ public:
+ static const uint8_t kPacketType = 204;
+ // 28 bytes for UDP header
+ // 12 bytes for RTCP app header
+ static const size_t kMaxDataSize = IP_PACKET_SIZE - 12 - 28;
+ App() : sub_type_(0), ssrc_(0), name_(0) {}
+
+ virtual ~App() {}
+
+ // 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) { ssrc_ = ssrc; }
+ void WithSubType(uint8_t subtype);
+ void WithName(uint32_t name) { name_ = name; }
+ void WithData(const uint8_t* data, size_t data_length);
+
+ uint8_t sub_type() const { return sub_type_; }
+ uint32_t ssrc() const { return ssrc_; }
+ uint32_t name() const { return name_; }
+ size_t data_size() const { return data_.size(); }
+ const uint8_t* data() const { return data_.data(); }
+
+ protected:
+ bool Create(uint8_t* packet,
+ size_t* index,
+ size_t max_length,
+ RtcpPacket::PacketReadyCallback* callback) const override;
+
+ private:
+ size_t BlockLength() const override { return 12 + data_.size(); }
+
+ uint8_t sub_type_;
+ uint32_t ssrc_;
+ uint32_t name_;
+ rtc::Buffer data_;
+
+ RTC_DISALLOW_COPY_AND_ASSIGN(App);
+};
+
+} // namespace rtcp
+} // namespace webrtc
+#endif // WEBRTC_MODULES_RTP_RTCP_SOURCE_RTCP_PACKET_APP_H_
diff --git a/webrtc/modules/rtp_rtcp/source/rtcp_packet/app_unittest.cc b/webrtc/modules/rtp_rtcp/source/rtcp_packet/app_unittest.cc
new file mode 100644
index 0000000000..4451fe8fb5
--- /dev/null
+++ b/webrtc/modules/rtp_rtcp/source/rtcp_packet/app_unittest.cc
@@ -0,0 +1,81 @@
+/*
+ * 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/app.h"
+
+#include <limits>
+
+#include "testing/gtest/include/gtest/gtest.h"
+#include "webrtc/modules/rtp_rtcp/source/rtcp_utility.h"
+
+using webrtc::rtcp::App;
+using webrtc::rtcp::RawPacket;
+using webrtc::RTCPUtility::RtcpCommonHeader;
+using webrtc::RTCPUtility::RtcpParseCommonHeader;
+
+namespace webrtc {
+namespace {
+
+const uint32_t kName = ((uint32_t)'n' << 24) | ((uint32_t)'a' << 16) |
+ ((uint32_t)'m' << 8) | (uint32_t)'e';
+const uint32_t kSenderSsrc = 0x12345678;
+
+class RtcpPacketAppTest : public ::testing::Test {
+ protected:
+ void BuildPacket() { packet = app.Build(); }
+ void ParsePacket() {
+ RtcpCommonHeader header;
+ EXPECT_TRUE(
+ RtcpParseCommonHeader(packet->Buffer(), packet->Length(), &header));
+ // Check there is exactly one RTCP packet in the buffer.
+ EXPECT_EQ(header.BlockSize(), packet->Length());
+ EXPECT_TRUE(parsed_.Parse(
+ header, packet->Buffer() + RtcpCommonHeader::kHeaderSizeBytes));
+ }
+
+ App app;
+ rtc::scoped_ptr<RawPacket> packet;
+ const App& parsed() { return parsed_; }
+
+ private:
+ App parsed_;
+};
+
+TEST_F(RtcpPacketAppTest, WithNoData) {
+ app.WithSubType(30);
+ app.WithName(kName);
+
+ BuildPacket();
+ ParsePacket();
+
+ EXPECT_EQ(30U, parsed().sub_type());
+ EXPECT_EQ(kName, parsed().name());
+ EXPECT_EQ(0u, parsed().data_size());
+}
+
+TEST_F(RtcpPacketAppTest, WithData) {
+ app.From(kSenderSsrc);
+ app.WithSubType(30);
+ app.WithName(kName);
+ const uint8_t kData[] = {'t', 'e', 's', 't', 'd', 'a', 't', 'a'};
+ const size_t kDataLength = sizeof(kData) / sizeof(kData[0]);
+ app.WithData(kData, kDataLength);
+
+ BuildPacket();
+ ParsePacket();
+
+ EXPECT_EQ(30U, parsed().sub_type());
+ EXPECT_EQ(kName, parsed().name());
+ EXPECT_EQ(kDataLength, parsed().data_size());
+ EXPECT_EQ(0, memcmp(kData, parsed().data(), kDataLength));
+}
+
+} // namespace
+} // namespace webrtc
diff --git a/webrtc/modules/rtp_rtcp/source/rtcp_packet/bye.cc b/webrtc/modules/rtp_rtcp/source/rtcp_packet/bye.cc
new file mode 100644
index 0000000000..4cfc921ce5
--- /dev/null
+++ b/webrtc/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/webrtc/modules/rtp_rtcp/source/rtcp_packet/bye.h b/webrtc/modules/rtp_rtcp/source/rtcp_packet/bye.h
new file mode 100644
index 0000000000..6b4a181330
--- /dev/null
+++ b/webrtc/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/webrtc/modules/rtp_rtcp/source/rtcp_packet/bye_unittest.cc b/webrtc/modules/rtp_rtcp/source/rtcp_packet/bye_unittest.cc
new file mode 100644
index 0000000000..d2ae8ed782
--- /dev/null
+++ b/webrtc/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(); }
+ 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/webrtc/modules/rtp_rtcp/source/rtcp_packet/compound_packet.cc b/webrtc/modules/rtp_rtcp/source/rtcp_packet/compound_packet.cc
new file mode 100644
index 0000000000..8f5afd5dd1
--- /dev/null
+++ b/webrtc/modules/rtp_rtcp/source/rtcp_packet/compound_packet.cc
@@ -0,0 +1,28 @@
+/*
+ * 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/compound_packet.h"
+
+namespace webrtc {
+namespace rtcp {
+
+bool CompoundPacket::Create(uint8_t* packet,
+ size_t* index,
+ size_t max_length,
+ RtcpPacket::PacketReadyCallback* callback) const {
+ return true;
+}
+
+size_t CompoundPacket::BlockLength() const {
+ return 0;
+}
+
+} // namespace rtcp
+} // namespace webrtc
diff --git a/webrtc/modules/rtp_rtcp/source/rtcp_packet/compound_packet.h b/webrtc/modules/rtp_rtcp/source/rtcp_packet/compound_packet.h
new file mode 100644
index 0000000000..f2f49a8ffb
--- /dev/null
+++ b/webrtc/modules/rtp_rtcp/source/rtcp_packet/compound_packet.h
@@ -0,0 +1,41 @@
+/*
+ * 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_COMPOUND_PACKET_H_
+#define WEBRTC_MODULES_RTP_RTCP_SOURCE_RTCP_PACKET_COMPOUND_PACKET_H_
+
+#include "webrtc/base/basictypes.h"
+#include "webrtc/modules/rtp_rtcp/source/rtcp_packet.h"
+
+namespace webrtc {
+namespace rtcp {
+
+class CompoundPacket : public RtcpPacket {
+ public:
+ CompoundPacket() : RtcpPacket() {}
+
+ virtual ~CompoundPacket() {}
+
+ protected:
+ bool Create(uint8_t* packet,
+ size_t* index,
+ size_t max_length,
+ RtcpPacket::PacketReadyCallback* callback) const override;
+
+ size_t BlockLength() const override;
+
+ private:
+ RTC_DISALLOW_COPY_AND_ASSIGN(CompoundPacket);
+};
+
+} // namespace rtcp
+} // namespace webrtc
+#endif // WEBRTC_MODULES_RTP_RTCP_SOURCE_RTCP_PACKET_COMPOUND_PACKET_H_
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
new file mode 100644
index 0000000000..83dc5f6ed3
--- /dev/null
+++ b/webrtc/modules/rtp_rtcp/source/rtcp_packet/compound_packet_unittest.cc
@@ -0,0 +1,157 @@
+/*
+ * 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/compound_packet.h"
+
+#include "testing/gtest/include/gtest/gtest.h"
+#include "webrtc/modules/rtp_rtcp/source/rtcp_packet.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 webrtc::rtcp::Bye;
+using webrtc::rtcp::CompoundPacket;
+using webrtc::rtcp::Fir;
+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;
+
+TEST(RtcpCompoundPacketTest, AppendPacket) {
+ Fir fir;
+ ReportBlock rb;
+ ReceiverReport rr;
+ rr.From(kSenderSsrc);
+ EXPECT_TRUE(rr.WithReportBlock(rb));
+ rr.Append(&fir);
+
+ rtc::scoped_ptr<RawPacket> packet(rr.Build());
+ RtcpPacketParser parser;
+ parser.Parse(packet->Buffer(), packet->Length());
+ EXPECT_EQ(1, parser.receiver_report()->num_packets());
+ EXPECT_EQ(kSenderSsrc, parser.receiver_report()->Ssrc());
+ EXPECT_EQ(1, parser.report_block()->num_packets());
+ EXPECT_EQ(1, parser.fir()->num_packets());
+}
+
+TEST(RtcpCompoundPacketTest, AppendPacketOnEmpty) {
+ CompoundPacket empty;
+ ReceiverReport rr;
+ rr.From(kSenderSsrc);
+ empty.Append(&rr);
+
+ rtc::scoped_ptr<RawPacket> packet(empty.Build());
+ RtcpPacketParser parser;
+ parser.Parse(packet->Buffer(), packet->Length());
+ EXPECT_EQ(1, parser.receiver_report()->num_packets());
+ EXPECT_EQ(0, parser.report_block()->num_packets());
+}
+
+TEST(RtcpCompoundPacketTest, AppendPacketWithOwnAppendedPacket) {
+ Fir fir;
+ Bye bye;
+ ReportBlock rb;
+
+ ReceiverReport rr;
+ EXPECT_TRUE(rr.WithReportBlock(rb));
+ rr.Append(&fir);
+
+ SenderReport sr;
+ sr.Append(&bye);
+ sr.Append(&rr);
+
+ 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(1, parser.receiver_report()->num_packets());
+ EXPECT_EQ(1, parser.report_block()->num_packets());
+ EXPECT_EQ(1, parser.bye()->num_packets());
+ EXPECT_EQ(1, parser.fir()->num_packets());
+}
+
+TEST(RtcpCompoundPacketTest, BuildWithInputBuffer) {
+ Fir fir;
+ ReportBlock rb;
+ ReceiverReport rr;
+ rr.From(kSenderSsrc);
+ EXPECT_TRUE(rr.WithReportBlock(rb));
+ rr.Append(&fir);
+
+ const size_t kRrLength = 8;
+ const size_t kReportBlockLength = 24;
+ const size_t kFirLength = 20;
+
+ class Verifier : public rtcp::RtcpPacket::PacketReadyCallback {
+ public:
+ void OnPacketReady(uint8_t* data, size_t length) override {
+ RtcpPacketParser parser;
+ parser.Parse(data, length);
+ EXPECT_EQ(1, parser.receiver_report()->num_packets());
+ EXPECT_EQ(1, parser.report_block()->num_packets());
+ EXPECT_EQ(1, parser.fir()->num_packets());
+ ++packets_created_;
+ }
+
+ int packets_created_ = 0;
+ } verifier;
+ const size_t kBufferSize = kRrLength + kReportBlockLength + kFirLength;
+ uint8_t buffer[kBufferSize];
+ EXPECT_TRUE(rr.BuildExternalBuffer(buffer, kBufferSize, &verifier));
+ EXPECT_EQ(1, verifier.packets_created_);
+}
+
+TEST(RtcpCompoundPacketTest, BuildWithTooSmallBuffer_FragmentedSend) {
+ Fir fir;
+ ReportBlock rb;
+ ReceiverReport rr;
+ rr.From(kSenderSsrc);
+ EXPECT_TRUE(rr.WithReportBlock(rb));
+ rr.Append(&fir);
+
+ const size_t kRrLength = 8;
+ const size_t kReportBlockLength = 24;
+
+ class Verifier : public rtcp::RtcpPacket::PacketReadyCallback {
+ public:
+ void OnPacketReady(uint8_t* data, size_t length) override {
+ RtcpPacketParser parser;
+ parser.Parse(data, length);
+ switch (packets_created_++) {
+ case 0:
+ EXPECT_EQ(1, parser.receiver_report()->num_packets());
+ EXPECT_EQ(1, parser.report_block()->num_packets());
+ EXPECT_EQ(0, parser.fir()->num_packets());
+ break;
+ case 1:
+ EXPECT_EQ(0, parser.receiver_report()->num_packets());
+ EXPECT_EQ(0, parser.report_block()->num_packets());
+ EXPECT_EQ(1, parser.fir()->num_packets());
+ break;
+ default:
+ ADD_FAILURE() << "OnPacketReady not expected to be called "
+ << packets_created_ << " times.";
+ }
+ }
+
+ int packets_created_ = 0;
+ } verifier;
+ const size_t kBufferSize = kRrLength + kReportBlockLength;
+ uint8_t buffer[kBufferSize];
+ EXPECT_TRUE(rr.BuildExternalBuffer(buffer, kBufferSize, &verifier));
+ EXPECT_EQ(2, verifier.packets_created_);
+}
+
+} // namespace webrtc
diff --git a/webrtc/modules/rtp_rtcp/source/rtcp_packet/dlrr.cc b/webrtc/modules/rtp_rtcp/source/rtcp_packet/dlrr.cc
new file mode 100644
index 0000000000..6d6c48fada
--- /dev/null
+++ b/webrtc/modules/rtp_rtcp/source/rtcp_packet/dlrr.cc
@@ -0,0 +1,100 @@
+/*
+ * 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/dlrr.h"
+
+#include "webrtc/base/checks.h"
+#include "webrtc/base/logging.h"
+#include "webrtc/modules/rtp_rtcp/source/byte_io.h"
+
+namespace webrtc {
+namespace rtcp {
+// 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
+bool Dlrr::Parse(const uint8_t* buffer, uint16_t block_length_32bits) {
+ RTC_DCHECK(buffer[0] == kBlockType);
+ // kReserved = buffer[1];
+ RTC_DCHECK_EQ(block_length_32bits,
+ ByteReader<uint16_t>::ReadBigEndian(&buffer[2]));
+ if (block_length_32bits % 3 != 0) {
+ LOG(LS_WARNING) << "Invalid size for dlrr block.";
+ return false;
+ }
+
+ size_t blocks_count = block_length_32bits / 3;
+ const uint8_t* read_at = buffer + kBlockHeaderLength;
+ sub_blocks_.resize(blocks_count);
+ for (SubBlock& sub_block : sub_blocks_) {
+ sub_block.ssrc = ByteReader<uint32_t>::ReadBigEndian(&read_at[0]);
+ sub_block.last_rr = ByteReader<uint32_t>::ReadBigEndian(&read_at[4]);
+ sub_block.delay_since_last_rr =
+ ByteReader<uint32_t>::ReadBigEndian(&read_at[8]);
+ read_at += kSubBlockLength;
+ }
+ return true;
+}
+
+size_t Dlrr::BlockLength() const {
+ if (sub_blocks_.empty())
+ return 0;
+ return kBlockHeaderLength + kSubBlockLength * sub_blocks_.size();
+}
+
+void Dlrr::Create(uint8_t* buffer) const {
+ if (sub_blocks_.empty()) // No subblocks, no need to write header either.
+ return;
+ // Create block header.
+ const uint8_t kReserved = 0;
+ buffer[0] = kBlockType;
+ buffer[1] = kReserved;
+ ByteWriter<uint16_t>::WriteBigEndian(&buffer[2], 3 * sub_blocks_.size());
+ // Create sub blocks.
+ uint8_t* write_at = buffer + kBlockHeaderLength;
+ for (const SubBlock& sub_block : sub_blocks_) {
+ ByteWriter<uint32_t>::WriteBigEndian(&write_at[0], sub_block.ssrc);
+ ByteWriter<uint32_t>::WriteBigEndian(&write_at[4], sub_block.last_rr);
+ ByteWriter<uint32_t>::WriteBigEndian(&write_at[8],
+ sub_block.delay_since_last_rr);
+ write_at += kSubBlockLength;
+ }
+ RTC_DCHECK_EQ(buffer + BlockLength(), write_at);
+}
+
+bool Dlrr::WithDlrrItem(uint32_t ssrc,
+ uint32_t last_rr,
+ uint32_t delay_last_rr) {
+ if (sub_blocks_.size() >= kMaxNumberOfDlrrItems) {
+ LOG(LS_WARNING) << "Max DLRR items reached.";
+ return false;
+ }
+ SubBlock block;
+ block.ssrc = ssrc;
+ block.last_rr = last_rr;
+ block.delay_since_last_rr = delay_last_rr;
+ sub_blocks_.push_back(block);
+ return true;
+}
+
+} // namespace rtcp
+} // namespace webrtc
diff --git a/webrtc/modules/rtp_rtcp/source/rtcp_packet/dlrr.h b/webrtc/modules/rtp_rtcp/source/rtcp_packet/dlrr.h
new file mode 100644
index 0000000000..9af2dedf3f
--- /dev/null
+++ b/webrtc/modules/rtp_rtcp/source/rtcp_packet/dlrr.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_DLRR_H_
+#define WEBRTC_MODULES_RTP_RTCP_SOURCE_RTCP_PACKET_DLRR_H_
+
+#include <vector>
+
+#include "webrtc/base/basictypes.h"
+
+namespace webrtc {
+namespace rtcp {
+
+// DLRR Report Block: Delay since the Last Receiver Report (RFC 3611).
+class Dlrr {
+ public:
+ struct SubBlock {
+ // RFC 3611 4.5
+ uint32_t ssrc;
+ uint32_t last_rr;
+ uint32_t delay_since_last_rr;
+ };
+
+ static const uint8_t kBlockType = 5;
+ static const size_t kMaxNumberOfDlrrItems = 100;
+
+ Dlrr() {}
+ Dlrr(const Dlrr& other) = default;
+ ~Dlrr() {}
+
+ Dlrr& operator=(const Dlrr& other) = default;
+
+ // Second parameter is value read from block header,
+ // i.e. size of block in 32bits excluding block header itself.
+ bool Parse(const uint8_t* buffer, uint16_t block_length_32bits);
+
+ size_t BlockLength() const;
+ // Fills buffer with the Dlrr.
+ // Consumes BlockLength() bytes.
+ void Create(uint8_t* buffer) const;
+
+ // Max 100 DLRR Items can be added per DLRR report block.
+ bool WithDlrrItem(uint32_t ssrc, uint32_t last_rr, uint32_t delay_last_rr);
+
+ const std::vector<SubBlock>& sub_blocks() const { return sub_blocks_; }
+
+ private:
+ static const size_t kBlockHeaderLength = 4;
+ static const size_t kSubBlockLength = 12;
+
+ std::vector<SubBlock> sub_blocks_;
+};
+} // namespace rtcp
+} // namespace webrtc
+#endif // WEBRTC_MODULES_RTP_RTCP_SOURCE_RTCP_PACKET_DLRR_H_
diff --git a/webrtc/modules/rtp_rtcp/source/rtcp_packet/dlrr_unittest.cc b/webrtc/modules/rtp_rtcp/source/rtcp_packet/dlrr_unittest.cc
new file mode 100644
index 0000000000..c7c139c560
--- /dev/null
+++ b/webrtc/modules/rtp_rtcp/source/rtcp_packet/dlrr_unittest.cc
@@ -0,0 +1,102 @@
+/*
+ * 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/dlrr.h"
+
+#include "testing/gtest/include/gtest/gtest.h"
+
+#include "webrtc/modules/rtp_rtcp/source/byte_io.h"
+
+using webrtc::rtcp::Dlrr;
+
+namespace webrtc {
+namespace {
+
+const uint32_t kSsrc = 0x12345678;
+const uint32_t kLastRR = 0x23344556;
+const uint32_t kDelay = 0x33343536;
+const uint8_t kBlock[] = {0x05, 0x00, 0x00, 0x03, 0x12, 0x34, 0x56, 0x78,
+ 0x23, 0x34, 0x45, 0x56, 0x33, 0x34, 0x35, 0x36};
+const size_t kBlockSizeBytes = sizeof(kBlock);
+
+TEST(RtcpPacketDlrrTest, Empty) {
+ Dlrr dlrr;
+
+ EXPECT_EQ(0u, dlrr.BlockLength());
+}
+
+TEST(RtcpPacketDlrrTest, Create) {
+ Dlrr dlrr;
+ EXPECT_TRUE(dlrr.WithDlrrItem(kSsrc, kLastRR, kDelay));
+
+ ASSERT_EQ(kBlockSizeBytes, dlrr.BlockLength());
+ uint8_t buffer[kBlockSizeBytes];
+
+ dlrr.Create(buffer);
+ EXPECT_EQ(0, memcmp(buffer, kBlock, kBlockSizeBytes));
+}
+
+TEST(RtcpPacketDlrrTest, Parse) {
+ Dlrr dlrr;
+ uint16_t block_length = ByteReader<uint16_t>::ReadBigEndian(&kBlock[2]);
+ EXPECT_TRUE(dlrr.Parse(kBlock, block_length));
+
+ EXPECT_EQ(1u, dlrr.sub_blocks().size());
+ const Dlrr::SubBlock& block = dlrr.sub_blocks().front();
+ EXPECT_EQ(kSsrc, block.ssrc);
+ EXPECT_EQ(kLastRR, block.last_rr);
+ EXPECT_EQ(kDelay, block.delay_since_last_rr);
+}
+
+TEST(RtcpPacketDlrrTest, ParseFailsOnBadSize) {
+ const size_t kBigBufferSize = 0x100; // More than enough.
+ uint8_t buffer[kBigBufferSize];
+ buffer[0] = Dlrr::kBlockType;
+ buffer[1] = 0; // Reserved.
+ buffer[2] = 0; // Most significant size byte.
+ for (uint8_t size = 3; size < 6; ++size) {
+ buffer[3] = size;
+ Dlrr dlrr;
+ // Parse should be successful only when size is multiple of 3.
+ EXPECT_EQ(size % 3 == 0, dlrr.Parse(buffer, static_cast<uint16_t>(size)));
+ }
+}
+
+TEST(RtcpPacketDlrrTest, FailsOnTooManySubBlocks) {
+ Dlrr dlrr;
+ for (size_t i = 1; i <= Dlrr::kMaxNumberOfDlrrItems; ++i) {
+ EXPECT_TRUE(dlrr.WithDlrrItem(kSsrc + i, kLastRR + i, kDelay + i));
+ }
+ EXPECT_FALSE(dlrr.WithDlrrItem(kSsrc, kLastRR, kDelay));
+}
+
+TEST(RtcpPacketDlrrTest, CreateAndParseMaxSubBlocks) {
+ const size_t kBufferSize = 0x1000; // More than enough.
+ uint8_t buffer[kBufferSize];
+
+ // Create.
+ Dlrr dlrr;
+ for (size_t i = 1; i <= Dlrr::kMaxNumberOfDlrrItems; ++i) {
+ EXPECT_TRUE(dlrr.WithDlrrItem(kSsrc + i, kLastRR + i, kDelay + i));
+ }
+ size_t used_buffer_size = dlrr.BlockLength();
+ ASSERT_LE(used_buffer_size, kBufferSize);
+ dlrr.Create(buffer);
+
+ // Parse.
+ Dlrr parsed;
+ uint16_t block_length = ByteReader<uint16_t>::ReadBigEndian(&buffer[2]);
+ EXPECT_EQ(used_buffer_size, (block_length + 1) * 4u);
+ EXPECT_TRUE(parsed.Parse(buffer, block_length));
+ EXPECT_TRUE(parsed.sub_blocks().size() == Dlrr::kMaxNumberOfDlrrItems);
+}
+
+} // namespace
+} // namespace webrtc
diff --git a/webrtc/modules/rtp_rtcp/source/rtcp_packet/extended_jitter_report.cc b/webrtc/modules/rtp_rtcp/source/rtcp_packet/extended_jitter_report.cc
new file mode 100644
index 0000000000..030f9f81fa
--- /dev/null
+++ b/webrtc/modules/rtp_rtcp/source/rtcp_packet/extended_jitter_report.cc
@@ -0,0 +1,95 @@
+/*
+ * 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/extended_jitter_report.h"
+
+#include "webrtc/base/checks.h"
+#include "webrtc/base/logging.h"
+#include "webrtc/modules/rtp_rtcp/source/byte_io.h"
+#include "webrtc/modules/rtp_rtcp/source/rtp_utility.h"
+
+using webrtc::RTCPUtility::RtcpCommonHeader;
+
+namespace webrtc {
+namespace rtcp {
+
+// Transmission Time Offsets in RTP Streams (RFC 5450).
+//
+// 0 1 2 3
+// 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+// hdr |V=2|P| RC | PT=IJ=195 | length |
+// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+// | inter-arrival jitter |
+// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+// . .
+// . .
+// . .
+// | inter-arrival jitter |
+// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+//
+// If present, this RTCP packet must be placed after a receiver report
+// (inside a compound RTCP packet), and MUST have the same value for RC
+// (reception report count) as the receiver report.
+
+bool ExtendedJitterReport::Parse(const RtcpCommonHeader& header,
+ const uint8_t* payload) {
+ RTC_DCHECK(header.packet_type == kPacketType);
+
+ const uint8_t jitters_count = header.count_or_format;
+ const size_t kJitterSizeBytes = 4u;
+
+ if (header.payload_size_bytes < jitters_count * kJitterSizeBytes) {
+ LOG(LS_WARNING) << "Packet is too small to contain all the jitter.";
+ return false;
+ }
+
+ inter_arrival_jitters_.resize(jitters_count);
+ for (size_t index = 0; index < jitters_count; ++index) {
+ inter_arrival_jitters_[index] =
+ ByteReader<uint32_t>::ReadBigEndian(&payload[index * kJitterSizeBytes]);
+ }
+
+ return true;
+}
+
+bool ExtendedJitterReport::WithJitter(uint32_t jitter) {
+ if (inter_arrival_jitters_.size() >= kMaxNumberOfJitters) {
+ LOG(LS_WARNING) << "Max inter-arrival jitter items reached.";
+ return false;
+ }
+ inter_arrival_jitters_.push_back(jitter);
+ return true;
+}
+
+bool ExtendedJitterReport::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();
+ size_t length = inter_arrival_jitters_.size();
+ CreateHeader(length, kPacketType, length, packet, index);
+
+ for (uint32_t jitter : inter_arrival_jitters_) {
+ ByteWriter<uint32_t>::WriteBigEndian(packet + *index, jitter);
+ *index += sizeof(uint32_t);
+ }
+ // Sanity check.
+ RTC_DCHECK_EQ(index_end, *index);
+ return true;
+}
+
+} // namespace rtcp
+} // namespace webrtc
diff --git a/webrtc/modules/rtp_rtcp/source/rtcp_packet/extended_jitter_report.h b/webrtc/modules/rtp_rtcp/source/rtcp_packet/extended_jitter_report.h
new file mode 100644
index 0000000000..49de7be1a8
--- /dev/null
+++ b/webrtc/modules/rtp_rtcp/source/rtcp_packet/extended_jitter_report.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_EXTENDED_JITTER_REPORT_H_
+#define WEBRTC_MODULES_RTP_RTCP_SOURCE_RTCP_PACKET_EXTENDED_JITTER_REPORT_H_
+
+#include <vector>
+
+#include "webrtc/base/checks.h"
+#include "webrtc/modules/rtp_rtcp/source/rtcp_packet.h"
+#include "webrtc/modules/rtp_rtcp/source/rtcp_utility.h"
+
+namespace webrtc {
+namespace rtcp {
+
+class ExtendedJitterReport : public RtcpPacket {
+ public:
+ static const uint8_t kPacketType = 195;
+
+ ExtendedJitterReport() : RtcpPacket() {}
+
+ virtual ~ExtendedJitterReport() {}
+
+ // 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.
+
+ bool WithJitter(uint32_t jitter);
+
+ size_t jitters_count() const { return inter_arrival_jitters_.size(); }
+ uint32_t jitter(size_t index) const {
+ RTC_DCHECK_LT(index, jitters_count());
+ return inter_arrival_jitters_[index];
+ }
+
+ protected:
+ bool Create(uint8_t* packet,
+ size_t* index,
+ size_t max_length,
+ RtcpPacket::PacketReadyCallback* callback) const override;
+
+ private:
+ static const int kMaxNumberOfJitters = 0x1f;
+
+ size_t BlockLength() const override {
+ return kHeaderLength + 4 * inter_arrival_jitters_.size();
+ }
+
+ std::vector<uint32_t> inter_arrival_jitters_;
+
+ RTC_DISALLOW_COPY_AND_ASSIGN(ExtendedJitterReport);
+};
+
+} // namespace rtcp
+} // namespace webrtc
+#endif // WEBRTC_MODULES_RTP_RTCP_SOURCE_RTCP_PACKET_EXTENDED_JITTER_REPORT_H_
diff --git a/webrtc/modules/rtp_rtcp/source/rtcp_packet/extended_jitter_report_unittest.cc b/webrtc/modules/rtp_rtcp/source/rtcp_packet/extended_jitter_report_unittest.cc
new file mode 100644
index 0000000000..09d7b6305f
--- /dev/null
+++ b/webrtc/modules/rtp_rtcp/source/rtcp_packet/extended_jitter_report_unittest.cc
@@ -0,0 +1,98 @@
+/*
+ * 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/extended_jitter_report.h"
+
+#include <limits>
+
+#include "testing/gtest/include/gtest/gtest.h"
+#include "webrtc/modules/rtp_rtcp/source/rtcp_utility.h"
+
+using webrtc::rtcp::RawPacket;
+using webrtc::rtcp::ExtendedJitterReport;
+using webrtc::RTCPUtility::RtcpCommonHeader;
+using webrtc::RTCPUtility::RtcpParseCommonHeader;
+
+namespace webrtc {
+namespace {
+
+class RtcpPacketExtendedJitterReportTest : public ::testing::Test {
+ protected:
+ void BuildPacket() { packet = ij.Build(); }
+ void ParsePacket() {
+ RtcpCommonHeader header;
+ EXPECT_TRUE(
+ RtcpParseCommonHeader(packet->Buffer(), packet->Length(), &header));
+ EXPECT_EQ(header.BlockSize(), packet->Length());
+ EXPECT_TRUE(parsed_.Parse(
+ header, packet->Buffer() + RtcpCommonHeader::kHeaderSizeBytes));
+ }
+
+ ExtendedJitterReport ij;
+ rtc::scoped_ptr<RawPacket> packet;
+ const ExtendedJitterReport& parsed() { return parsed_; }
+
+ private:
+ ExtendedJitterReport parsed_;
+};
+
+TEST_F(RtcpPacketExtendedJitterReportTest, NoItem) {
+ // No initialization because packet is empty.
+ BuildPacket();
+ ParsePacket();
+
+ EXPECT_EQ(0u, parsed().jitters_count());
+}
+
+TEST_F(RtcpPacketExtendedJitterReportTest, OneItem) {
+ EXPECT_TRUE(ij.WithJitter(0x11121314));
+
+ BuildPacket();
+ ParsePacket();
+
+ EXPECT_EQ(1u, parsed().jitters_count());
+ EXPECT_EQ(0x11121314U, parsed().jitter(0));
+}
+
+TEST_F(RtcpPacketExtendedJitterReportTest, TwoItems) {
+ EXPECT_TRUE(ij.WithJitter(0x11121418));
+ EXPECT_TRUE(ij.WithJitter(0x22242628));
+
+ BuildPacket();
+ ParsePacket();
+
+ EXPECT_EQ(2u, parsed().jitters_count());
+ EXPECT_EQ(0x11121418U, parsed().jitter(0));
+ EXPECT_EQ(0x22242628U, parsed().jitter(1));
+}
+
+TEST_F(RtcpPacketExtendedJitterReportTest, TooManyItems) {
+ const int kMaxIjItems = (1 << 5) - 1;
+ for (int i = 0; i < kMaxIjItems; ++i) {
+ EXPECT_TRUE(ij.WithJitter(i));
+ }
+ EXPECT_FALSE(ij.WithJitter(kMaxIjItems));
+}
+
+TEST_F(RtcpPacketExtendedJitterReportTest, ParseFailWithTooManyItems) {
+ ij.WithJitter(0x11121418);
+ BuildPacket();
+ RtcpCommonHeader header;
+ RtcpParseCommonHeader(packet->Buffer(), packet->Length(), &header);
+ header.count_or_format++; // Damage package.
+
+ ExtendedJitterReport parsed;
+
+ EXPECT_FALSE(parsed.Parse(
+ header, packet->Buffer() + RtcpCommonHeader::kHeaderSizeBytes));
+}
+
+} // namespace
+} // namespace webrtc
diff --git a/webrtc/modules/rtp_rtcp/source/rtcp_packet/nack.cc b/webrtc/modules/rtp_rtcp/source/rtcp_packet/nack.cc
new file mode 100644
index 0000000000..8b9b354a06
--- /dev/null
+++ b/webrtc/modules/rtp_rtcp/source/rtcp_packet/nack.cc
@@ -0,0 +1,163 @@
+/*
+ * 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/nack.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::RtcpCommonHeader;
+
+namespace webrtc {
+namespace rtcp {
+
+// RFC 4585: Feedback format.
+//
+// Common packet format:
+//
+// 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 | PT | length |
+// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+// 0 | SSRC of packet sender |
+// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+// 4 | SSRC of media source |
+// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+// : Feedback Control Information (FCI) :
+// : :
+//
+// Generic NACK (RFC 4585).
+//
+// FCI:
+// 0 1 2 3
+// 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+// | PID | BLP |
+// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+bool Nack::Parse(const RtcpCommonHeader& header, const uint8_t* payload) {
+ RTC_DCHECK(header.packet_type == kPacketType);
+ RTC_DCHECK(header.count_or_format == kFeedbackMessageType);
+
+ if (header.payload_size_bytes < kCommonFeedbackLength + kNackItemLength) {
+ LOG(LS_WARNING) << "Payload length " << header.payload_size_bytes
+ << " is too small for a Nack.";
+ return false;
+ }
+ size_t nack_items =
+ (header.payload_size_bytes - kCommonFeedbackLength) / kNackItemLength;
+
+ ParseCommonFeedback(payload);
+ const uint8_t* next_nack = payload + kCommonFeedbackLength;
+
+ packet_ids_.clear();
+ packed_.resize(nack_items);
+ for (size_t index = 0; index < nack_items; ++index) {
+ packed_[index].first_pid = ByteReader<uint16_t>::ReadBigEndian(next_nack);
+ packed_[index].bitmask = ByteReader<uint16_t>::ReadBigEndian(next_nack + 2);
+ next_nack += kNackItemLength;
+ }
+ Unpack();
+
+ return true;
+}
+
+bool Nack::Create(uint8_t* packet,
+ size_t* index,
+ size_t max_length,
+ RtcpPacket::PacketReadyCallback* callback) const {
+ RTC_DCHECK(!packed_.empty());
+ // If nack list can't fit in packet, try to fragment.
+ size_t nack_index = 0;
+ const size_t kCommonFbFmtLength = kHeaderLength + kCommonFeedbackLength;
+ do {
+ size_t bytes_left_in_buffer = max_length - *index;
+ if (bytes_left_in_buffer < kCommonFbFmtLength + kNackItemLength) {
+ if (!OnBufferFull(packet, index, callback))
+ return false;
+ continue;
+ }
+ size_t num_nack_fields =
+ std::min((bytes_left_in_buffer - kCommonFbFmtLength) / kNackItemLength,
+ packed_.size() - nack_index);
+
+ size_t size_bytes =
+ (num_nack_fields * kNackItemLength) + kCommonFbFmtLength;
+ size_t header_length = ((size_bytes + 3) / 4) - 1; // As 32bit words - 1
+ CreateHeader(kFeedbackMessageType, kPacketType, header_length, packet,
+ index);
+ CreateCommonFeedback(packet + *index);
+ *index += kCommonFeedbackLength;
+ size_t end_index = nack_index + num_nack_fields;
+ for (; nack_index < end_index; ++nack_index) {
+ const auto& item = packed_[nack_index];
+ ByteWriter<uint16_t>::WriteBigEndian(packet + *index + 0, item.first_pid);
+ ByteWriter<uint16_t>::WriteBigEndian(packet + *index + 2, item.bitmask);
+ *index += kNackItemLength;
+ }
+ RTC_DCHECK_LE(*index, max_length);
+ } while (nack_index < packed_.size());
+
+ return true;
+}
+
+size_t Nack::BlockLength() const {
+ return (packed_.size() * kNackItemLength) + kCommonFeedbackLength +
+ kHeaderLength;
+}
+
+void Nack::WithList(const uint16_t* nack_list, size_t length) {
+ RTC_DCHECK(nack_list);
+ RTC_DCHECK(packet_ids_.empty());
+ RTC_DCHECK(packed_.empty());
+ packet_ids_.assign(nack_list, nack_list + length);
+ Pack();
+}
+
+void Nack::Pack() {
+ RTC_DCHECK(!packet_ids_.empty());
+ RTC_DCHECK(packed_.empty());
+ auto it = packet_ids_.begin();
+ const auto end = packet_ids_.end();
+ while (it != end) {
+ PackedNack item;
+ item.first_pid = *it++;
+ // Bitmask specifies losses in any of the 16 packets following the pid.
+ item.bitmask = 0;
+ while (it != end) {
+ uint16_t shift = static_cast<uint16_t>(*it - item.first_pid - 1);
+ if (shift <= 15) {
+ item.bitmask |= (1 << shift);
+ ++it;
+ } else {
+ break;
+ }
+ }
+ packed_.push_back(item);
+ }
+}
+
+void Nack::Unpack() {
+ RTC_DCHECK(packet_ids_.empty());
+ RTC_DCHECK(!packed_.empty());
+ for (const PackedNack& item : packed_) {
+ packet_ids_.push_back(item.first_pid);
+ uint16_t pid = item.first_pid + 1;
+ for (uint16_t bitmask = item.bitmask; bitmask != 0; bitmask >>= 1, ++pid)
+ if (bitmask & 1)
+ packet_ids_.push_back(pid);
+ }
+}
+
+} // namespace rtcp
+} // namespace webrtc
diff --git a/webrtc/modules/rtp_rtcp/source/rtcp_packet/nack.h b/webrtc/modules/rtp_rtcp/source/rtcp_packet/nack.h
new file mode 100644
index 0000000000..fb2be113a2
--- /dev/null
+++ b/webrtc/modules/rtp_rtcp/source/rtcp_packet/nack.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_NACK_H_
+#define WEBRTC_MODULES_RTP_RTCP_SOURCE_RTCP_PACKET_NACK_H_
+
+#include <vector>
+
+#include "webrtc/base/basictypes.h"
+#include "webrtc/modules/rtp_rtcp/source/rtcp_packet/rtpfb.h"
+#include "webrtc/modules/rtp_rtcp/source/rtcp_utility.h"
+
+namespace webrtc {
+namespace rtcp {
+
+class Nack : public Rtpfb {
+ public:
+ const uint8_t kFeedbackMessageType = 1;
+ Nack() {}
+
+ virtual ~Nack() {}
+
+ // 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 WithList(const uint16_t* nack_list, size_t length);
+ const std::vector<uint16_t>& packet_ids() const { return packet_ids_; }
+
+ protected:
+ bool Create(uint8_t* packet,
+ size_t* index,
+ size_t max_length,
+ RtcpPacket::PacketReadyCallback* callback) const override;
+
+ size_t BlockLength() const override;
+
+ private:
+ const size_t kNackItemLength = 4;
+ struct PackedNack {
+ uint16_t first_pid;
+ uint16_t bitmask;
+ };
+
+ void Pack(); // Fills packed_ using packed_ids_. (used in WithList).
+ void Unpack(); // Fills packet_ids_ using packed_. (used in Parse).
+
+ std::vector<PackedNack> packed_;
+ std::vector<uint16_t> packet_ids_;
+
+ RTC_DISALLOW_COPY_AND_ASSIGN(Nack);
+};
+
+} // namespace rtcp
+} // namespace webrtc
+#endif // WEBRTC_MODULES_RTP_RTCP_SOURCE_RTCP_PACKET_NACK_H_
diff --git a/webrtc/modules/rtp_rtcp/source/rtcp_packet/nack_unittest.cc b/webrtc/modules/rtp_rtcp/source/rtcp_packet/nack_unittest.cc
new file mode 100644
index 0000000000..01e30f5644
--- /dev/null
+++ b/webrtc/modules/rtp_rtcp/source/rtcp_packet/nack_unittest.cc
@@ -0,0 +1,190 @@
+/*
+ * 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/nack.h"
+
+#include "testing/gmock/include/gmock/gmock.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+using ::testing::_;
+using ::testing::ElementsAreArray;
+using ::testing::Invoke;
+using ::testing::UnorderedElementsAreArray;
+
+using webrtc::rtcp::Nack;
+using webrtc::rtcp::RawPacket;
+using webrtc::RTCPUtility::RtcpCommonHeader;
+using webrtc::RTCPUtility::RtcpParseCommonHeader;
+
+namespace webrtc {
+namespace {
+
+const uint32_t kSenderSsrc = 0x12345678;
+const uint32_t kRemoteSsrc = 0x23456789;
+
+const uint16_t kList[] = {0, 1, 3, 8, 16};
+const size_t kListLength = sizeof(kList) / sizeof(kList[0]);
+const uint8_t kPacket[] = {0x81, 205, 0x00, 0x03, 0x12, 0x34, 0x56, 0x78,
+ 0x23, 0x45, 0x67, 0x89, 0x00, 0x00, 0x80, 0x85};
+const size_t kPacketLength = sizeof(kPacket);
+
+const uint16_t kWrapList[] = {0xffdc, 0xffec, 0xfffe, 0xffff, 0x0000,
+ 0x0001, 0x0003, 0x0014, 0x0064};
+const size_t kWrapListLength = sizeof(kWrapList) / sizeof(kWrapList[0]);
+const uint8_t kWrapPacket[] = {0x81, 205, 0x00, 0x06, 0x12, 0x34, 0x56, 0x78,
+ 0x23, 0x45, 0x67, 0x89, 0xff, 0xdc, 0x80, 0x00,
+ 0xff, 0xfe, 0x00, 0x17, 0x00, 0x14, 0x00, 0x00,
+ 0x00, 0x64, 0x00, 0x00};
+const size_t kWrapPacketLength = sizeof(kWrapPacket);
+
+TEST(RtcpPacketNackTest, Create) {
+ Nack nack;
+ nack.From(kSenderSsrc);
+ nack.To(kRemoteSsrc);
+ nack.WithList(kList, kListLength);
+
+ rtc::scoped_ptr<RawPacket> packet = nack.Build();
+
+ EXPECT_EQ(kPacketLength, packet->Length());
+ EXPECT_EQ(0, memcmp(kPacket, packet->Buffer(), kPacketLength));
+}
+
+TEST(RtcpPacketNackTest, Parse) {
+ RtcpCommonHeader header;
+ EXPECT_TRUE(RtcpParseCommonHeader(kPacket, kPacketLength, &header));
+ EXPECT_EQ(kPacketLength, header.BlockSize());
+ Nack parsed;
+
+ EXPECT_TRUE(
+ parsed.Parse(header, kPacket + RtcpCommonHeader::kHeaderSizeBytes));
+ const Nack& const_parsed = parsed;
+
+ EXPECT_EQ(kSenderSsrc, const_parsed.sender_ssrc());
+ EXPECT_EQ(kRemoteSsrc, const_parsed.media_ssrc());
+ EXPECT_THAT(const_parsed.packet_ids(), ElementsAreArray(kList));
+}
+
+TEST(RtcpPacketNackTest, CreateWrap) {
+ Nack nack;
+ nack.From(kSenderSsrc);
+ nack.To(kRemoteSsrc);
+ nack.WithList(kWrapList, kWrapListLength);
+
+ rtc::scoped_ptr<RawPacket> packet = nack.Build();
+
+ EXPECT_EQ(kWrapPacketLength, packet->Length());
+ EXPECT_EQ(0, memcmp(kWrapPacket, packet->Buffer(), kWrapPacketLength));
+}
+
+TEST(RtcpPacketNackTest, ParseWrap) {
+ RtcpCommonHeader header;
+ EXPECT_TRUE(RtcpParseCommonHeader(kWrapPacket, kWrapPacketLength, &header));
+ EXPECT_EQ(kWrapPacketLength, header.BlockSize());
+
+ Nack parsed;
+ EXPECT_TRUE(
+ parsed.Parse(header, kWrapPacket + RtcpCommonHeader::kHeaderSizeBytes));
+
+ EXPECT_EQ(kSenderSsrc, parsed.sender_ssrc());
+ EXPECT_EQ(kRemoteSsrc, parsed.media_ssrc());
+ EXPECT_THAT(parsed.packet_ids(), ElementsAreArray(kWrapList));
+}
+
+TEST(RtcpPacketNackTest, BadOrder) {
+ // Does not guarantee optimal packing, but should guarantee correctness.
+ const uint16_t kUnorderedList[] = {1, 25, 13, 12, 9, 27, 29};
+ const size_t kUnorderedListLength =
+ sizeof(kUnorderedList) / sizeof(kUnorderedList[0]);
+ Nack nack;
+ nack.From(kSenderSsrc);
+ nack.To(kRemoteSsrc);
+ nack.WithList(kUnorderedList, kUnorderedListLength);
+
+ rtc::scoped_ptr<RawPacket> packet = nack.Build();
+
+ Nack parsed;
+ RtcpCommonHeader header;
+ EXPECT_TRUE(
+ RtcpParseCommonHeader(packet->Buffer(), packet->Length(), &header));
+ EXPECT_TRUE(parsed.Parse(
+ header, packet->Buffer() + RtcpCommonHeader::kHeaderSizeBytes));
+
+ EXPECT_EQ(kSenderSsrc, parsed.sender_ssrc());
+ EXPECT_EQ(kRemoteSsrc, parsed.media_ssrc());
+ EXPECT_THAT(parsed.packet_ids(), UnorderedElementsAreArray(kUnorderedList));
+}
+
+TEST(RtcpPacketNackTest, CreateFragmented) {
+ Nack nack;
+ const uint16_t kList[] = {1, 100, 200, 300, 400};
+ const uint16_t kListLength = sizeof(kList) / sizeof(kList[0]);
+ nack.From(kSenderSsrc);
+ nack.To(kRemoteSsrc);
+ nack.WithList(kList, kListLength);
+
+ class MockPacketReadyCallback : public rtcp::RtcpPacket::PacketReadyCallback {
+ public:
+ MOCK_METHOD2(OnPacketReady, void(uint8_t*, size_t));
+ } verifier;
+
+ class NackVerifier {
+ public:
+ explicit NackVerifier(std::vector<uint16_t> ids) : ids_(ids) {}
+ void operator()(uint8_t* data, size_t length) {
+ RtcpCommonHeader header;
+ EXPECT_TRUE(RtcpParseCommonHeader(data, length, &header));
+ EXPECT_EQ(length, header.BlockSize());
+ Nack nack;
+ EXPECT_TRUE(
+ nack.Parse(header, data + RtcpCommonHeader::kHeaderSizeBytes));
+ EXPECT_EQ(kSenderSsrc, nack.sender_ssrc());
+ EXPECT_EQ(kRemoteSsrc, nack.media_ssrc());
+ EXPECT_THAT(nack.packet_ids(), ElementsAreArray(ids_));
+ }
+ std::vector<uint16_t> ids_;
+ } packet1({1, 100, 200}), packet2({300, 400});
+
+ EXPECT_CALL(verifier, OnPacketReady(_, _))
+ .WillOnce(Invoke(packet1))
+ .WillOnce(Invoke(packet2));
+ const size_t kBufferSize = 12 + (3 * 4); // Fits common header + 3 nack items
+ uint8_t buffer[kBufferSize];
+ EXPECT_TRUE(nack.BuildExternalBuffer(buffer, kBufferSize, &verifier));
+}
+
+TEST(RtcpPacketNackTest, CreateFailsWithTooSmallBuffer) {
+ const uint16_t kList[] = {1};
+ const size_t kMinNackBlockSize = 16;
+ Nack nack;
+ nack.From(kSenderSsrc);
+ nack.To(kRemoteSsrc);
+ nack.WithList(kList, 1);
+ class Verifier : public rtcp::RtcpPacket::PacketReadyCallback {
+ public:
+ void OnPacketReady(uint8_t* data, size_t length) override {
+ ADD_FAILURE() << "Buffer should be too small.";
+ }
+ } verifier;
+ uint8_t buffer[kMinNackBlockSize - 1];
+ EXPECT_FALSE(
+ nack.BuildExternalBuffer(buffer, kMinNackBlockSize - 1, &verifier));
+}
+
+TEST(RtcpPacketNackTest, ParseFailsWithTooSmallBuffer) {
+ RtcpCommonHeader header;
+ EXPECT_TRUE(RtcpParseCommonHeader(kPacket, kPacketLength, &header));
+ header.payload_size_bytes--; // Damage the packet
+ Nack parsed;
+ EXPECT_FALSE(
+ parsed.Parse(header, kPacket + RtcpCommonHeader::kHeaderSizeBytes));
+}
+
+} // namespace
+} // namespace webrtc
diff --git a/webrtc/modules/rtp_rtcp/source/rtcp_packet/pli.cc b/webrtc/modules/rtp_rtcp/source/rtcp_packet/pli.cc
new file mode 100644
index 0000000000..3673491058
--- /dev/null
+++ b/webrtc/modules/rtp_rtcp/source/rtcp_packet/pli.cc
@@ -0,0 +1,70 @@
+/*
+ * 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/pli.h"
+
+#include "webrtc/base/checks.h"
+#include "webrtc/base/logging.h"
+
+using webrtc::RTCPUtility::RtcpCommonHeader;
+
+namespace webrtc {
+namespace rtcp {
+
+// RFC 4585: Feedback format.
+//
+// Common packet format:
+//
+// 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 | PT | length |
+// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+// | SSRC of packet sender |
+// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+// | SSRC of media source |
+// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+// : Feedback Control Information (FCI) :
+// : :
+
+//
+// Picture loss indication (PLI) (RFC 4585).
+// FCI: no feedback control information.
+bool Pli::Parse(const RtcpCommonHeader& header, const uint8_t* payload) {
+ RTC_DCHECK(header.packet_type == kPacketType);
+ RTC_DCHECK(header.count_or_format == kFeedbackMessageType);
+
+ if (header.payload_size_bytes < kCommonFeedbackLength) {
+ LOG(LS_WARNING) << "Packet is too small to be a valid PLI packet";
+ return false;
+ }
+
+ ParseCommonFeedback(payload);
+ return true;
+}
+
+bool Pli::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(kFeedbackMessageType, kPacketType, HeaderLength(), packet,
+ index);
+ CreateCommonFeedback(packet + *index);
+ *index += kCommonFeedbackLength;
+ return true;
+}
+
+} // namespace rtcp
+} // namespace webrtc
diff --git a/webrtc/modules/rtp_rtcp/source/rtcp_packet/pli.h b/webrtc/modules/rtp_rtcp/source/rtcp_packet/pli.h
new file mode 100644
index 0000000000..5567825830
--- /dev/null
+++ b/webrtc/modules/rtp_rtcp/source/rtcp_packet/pli.h
@@ -0,0 +1,49 @@
+/*
+ * 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_PLI_H_
+#define WEBRTC_MODULES_RTP_RTCP_SOURCE_RTCP_PACKET_PLI_H_
+
+#include "webrtc/base/basictypes.h"
+#include "webrtc/modules/rtp_rtcp/source/rtcp_packet/psfb.h"
+
+namespace webrtc {
+namespace rtcp {
+
+// Picture loss indication (PLI) (RFC 4585).
+class Pli : public Psfb {
+ public:
+ static const uint8_t kFeedbackMessageType = 1;
+
+ Pli() {}
+ virtual ~Pli() {}
+
+ // 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.
+
+ protected:
+ bool Create(uint8_t* packet,
+ size_t* index,
+ size_t max_length,
+ RtcpPacket::PacketReadyCallback* callback) const override;
+
+ private:
+ size_t BlockLength() const override {
+ return kHeaderLength + kCommonFeedbackLength;
+ }
+
+ RTC_DISALLOW_COPY_AND_ASSIGN(Pli);
+};
+
+} // namespace rtcp
+} // namespace webrtc
+#endif // WEBRTC_MODULES_RTP_RTCP_SOURCE_RTCP_PACKET_PLI_H_
diff --git a/webrtc/modules/rtp_rtcp/source/rtcp_packet/pli_unittest.cc b/webrtc/modules/rtp_rtcp/source/rtcp_packet/pli_unittest.cc
new file mode 100644
index 0000000000..1c47c3ffb1
--- /dev/null
+++ b/webrtc/modules/rtp_rtcp/source/rtcp_packet/pli_unittest.cc
@@ -0,0 +1,66 @@
+/*
+ * 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/pli.h"
+
+#include "testing/gtest/include/gtest/gtest.h"
+#include "webrtc/modules/rtp_rtcp/source/rtcp_utility.h"
+
+using webrtc::rtcp::Pli;
+using webrtc::rtcp::RawPacket;
+using webrtc::RTCPUtility::RtcpCommonHeader;
+using webrtc::RTCPUtility::RtcpParseCommonHeader;
+
+namespace webrtc {
+namespace {
+
+const uint32_t kSenderSsrc = 0x12345678;
+const uint32_t kRemoteSsrc = 0x23456789;
+// Manually created Pli packet matching constants above.
+const uint8_t kPacket[] = {0x81, 206, 0x00, 0x02,
+ 0x12, 0x34, 0x56, 0x78,
+ 0x23, 0x45, 0x67, 0x89};
+const size_t kPacketLength = sizeof(kPacket);
+
+TEST(RtcpPacketPliTest, Parse) {
+ RtcpCommonHeader header;
+ EXPECT_TRUE(RtcpParseCommonHeader(kPacket, kPacketLength, &header));
+ Pli mutable_parsed;
+ EXPECT_TRUE(mutable_parsed.Parse(
+ header, kPacket + RtcpCommonHeader::kHeaderSizeBytes));
+ const Pli& parsed = mutable_parsed; // Read values from constant object.
+
+ EXPECT_EQ(kSenderSsrc, parsed.sender_ssrc());
+ EXPECT_EQ(kRemoteSsrc, parsed.media_ssrc());
+}
+
+TEST(RtcpPacketPliTest, Create) {
+ Pli pli;
+ pli.From(kSenderSsrc);
+ pli.To(kRemoteSsrc);
+
+ rtc::scoped_ptr<RawPacket> packet(pli.Build());
+
+ ASSERT_EQ(kPacketLength, packet->Length());
+ EXPECT_EQ(0, memcmp(kPacket, packet->Buffer(), kPacketLength));
+}
+
+TEST(RtcpPacketPliTest, ParseFailsOnTooSmallPacket) {
+ RtcpCommonHeader header;
+ EXPECT_TRUE(RtcpParseCommonHeader(kPacket, kPacketLength, &header));
+ header.payload_size_bytes--;
+
+ Pli parsed;
+ EXPECT_FALSE(
+ parsed.Parse(header, kPacket + RtcpCommonHeader::kHeaderSizeBytes));
+}
+
+} // namespace
+} // namespace webrtc
diff --git a/webrtc/modules/rtp_rtcp/source/rtcp_packet/psfb.cc b/webrtc/modules/rtp_rtcp/source/rtcp_packet/psfb.cc
new file mode 100644
index 0000000000..d1ee401dab
--- /dev/null
+++ b/webrtc/modules/rtp_rtcp/source/rtcp_packet/psfb.cc
@@ -0,0 +1,45 @@
+/*
+ * 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/psfb.h"
+
+#include "webrtc/modules/rtp_rtcp/source/byte_io.h"
+
+namespace webrtc {
+namespace rtcp {
+
+// RFC 4585: Feedback format.
+//
+// Common packet format:
+//
+// 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 | PT | length |
+// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+// 0 | SSRC of packet sender |
+// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+// 4 | SSRC of media source |
+// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+// : Feedback Control Information (FCI) :
+// : :
+
+void Psfb::ParseCommonFeedback(const uint8_t* payload) {
+ sender_ssrc_ = ByteReader<uint32_t>::ReadBigEndian(&payload[0]);
+ media_ssrc_ = ByteReader<uint32_t>::ReadBigEndian(&payload[4]);
+}
+
+void Psfb::CreateCommonFeedback(uint8_t* payload) const {
+ ByteWriter<uint32_t>::WriteBigEndian(&payload[0], sender_ssrc_);
+ ByteWriter<uint32_t>::WriteBigEndian(&payload[4], media_ssrc_);
+}
+
+} // namespace rtcp
+} // namespace webrtc
diff --git a/webrtc/modules/rtp_rtcp/source/rtcp_packet/psfb.h b/webrtc/modules/rtp_rtcp/source/rtcp_packet/psfb.h
new file mode 100644
index 0000000000..dddcdecba6
--- /dev/null
+++ b/webrtc/modules/rtp_rtcp/source/rtcp_packet/psfb.h
@@ -0,0 +1,48 @@
+/*
+ * 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_PSFB_H_
+#define WEBRTC_MODULES_RTP_RTCP_SOURCE_RTCP_PACKET_PSFB_H_
+
+#include "webrtc/base/basictypes.h"
+#include "webrtc/modules/rtp_rtcp/source/rtcp_packet.h"
+
+namespace webrtc {
+namespace rtcp {
+
+// PSFB: Payload-specific feedback message.
+// RFC 4585, Section 6.3.
+class Psfb : public RtcpPacket {
+ public:
+ static const uint8_t kPacketType = 206;
+
+ Psfb() : sender_ssrc_(0), media_ssrc_(0) {}
+ virtual ~Psfb() {}
+
+ void From(uint32_t ssrc) { sender_ssrc_ = ssrc; }
+ void To(uint32_t ssrc) { media_ssrc_ = ssrc; }
+
+ uint32_t sender_ssrc() const { return sender_ssrc_; }
+ uint32_t media_ssrc() const { return media_ssrc_; }
+
+ protected:
+ static const size_t kCommonFeedbackLength = 8;
+ void ParseCommonFeedback(const uint8_t* payload);
+ void CreateCommonFeedback(uint8_t* payload) const;
+
+ private:
+ uint32_t sender_ssrc_;
+ uint32_t media_ssrc_;
+};
+
+} // namespace rtcp
+} // namespace webrtc
+#endif // WEBRTC_MODULES_RTP_RTCP_SOURCE_RTCP_PACKET_PSFB_H_
diff --git a/webrtc/modules/rtp_rtcp/source/rtcp_packet/receiver_report.cc b/webrtc/modules/rtp_rtcp/source/rtcp_packet/receiver_report.cc
new file mode 100644
index 0000000000..ef64b4f51b
--- /dev/null
+++ b/webrtc/modules/rtp_rtcp/source/rtcp_packet/receiver_report.cc
@@ -0,0 +1,89 @@
+/*
+ * 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/receiver_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 {
+
+//
+// RTCP receiver report (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=RR=201 | length |
+// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+// | SSRC of packet sender |
+// +=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+
+// | report block(s) |
+// | .... |
+bool ReceiverReport::Parse(const RTCPUtility::RtcpCommonHeader& header,
+ const uint8_t* payload) {
+ RTC_DCHECK(header.packet_type == kPacketType);
+
+ const uint8_t report_blocks_count = header.count_or_format;
+
+ if (header.payload_size_bytes <
+ kRrBaseLength + report_blocks_count * ReportBlock::kLength) {
+ LOG(LS_WARNING) << "Packet is too small to contain all the data.";
+ return false;
+ }
+
+ sender_ssrc_ = ByteReader<uint32_t>::ReadBigEndian(payload);
+
+ const uint8_t* next_report_block = payload + kRrBaseLength;
+
+ report_blocks_.resize(report_blocks_count);
+ for (ReportBlock& block : report_blocks_) {
+ block.Parse(next_report_block, ReportBlock::kLength);
+ next_report_block += ReportBlock::kLength;
+ }
+
+ RTC_DCHECK_LE(next_report_block, payload + header.payload_size_bytes);
+ return true;
+}
+
+bool ReceiverReport::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(report_blocks_.size(), kPacketType, HeaderLength(), packet,
+ index);
+ ByteWriter<uint32_t>::WriteBigEndian(packet + *index, sender_ssrc_);
+ *index += kRrBaseLength;
+ for (const ReportBlock& block : report_blocks_) {
+ block.Create(packet + *index);
+ *index += ReportBlock::kLength;
+ }
+ return true;
+}
+
+bool ReceiverReport::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/receiver_report.h b/webrtc/modules/rtp_rtcp/source/rtcp_packet/receiver_report.h
new file mode 100644
index 0000000000..172a84ea2f
--- /dev/null
+++ b/webrtc/modules/rtp_rtcp/source/rtcp_packet/receiver_report.h
@@ -0,0 +1,66 @@
+/*
+ * 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_RECEIVER_REPORT_H_
+#define WEBRTC_MODULES_RTP_RTCP_SOURCE_RTCP_PACKET_RECEIVER_REPORT_H_
+
+#include <vector>
+
+#include "webrtc/base/basictypes.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"
+
+namespace webrtc {
+namespace rtcp {
+
+class ReceiverReport : public RtcpPacket {
+ public:
+ static const uint8_t kPacketType = 201;
+ ReceiverReport() : sender_ssrc_(0) {}
+
+ virtual ~ReceiverReport() {}
+
+ // 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 WithReportBlock(const ReportBlock& block);
+
+ uint32_t sender_ssrc() const { return sender_ssrc_; }
+ 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 kRrBaseLength = 4;
+ static const size_t kMaxNumberOfReportBlocks = 0x1F;
+
+ size_t BlockLength() const {
+ return kHeaderLength + kRrBaseLength +
+ report_blocks_.size() * ReportBlock::kLength;
+ }
+
+ uint32_t sender_ssrc_;
+ std::vector<ReportBlock> report_blocks_;
+
+ RTC_DISALLOW_COPY_AND_ASSIGN(ReceiverReport);
+};
+
+} // namespace rtcp
+} // namespace webrtc
+#endif // WEBRTC_MODULES_RTP_RTCP_SOURCE_RTCP_PACKET_RECEIVER_REPORT_H_
diff --git a/webrtc/modules/rtp_rtcp/source/rtcp_packet/receiver_report_unittest.cc b/webrtc/modules/rtp_rtcp/source/rtcp_packet/receiver_report_unittest.cc
new file mode 100644
index 0000000000..ff3da600a5
--- /dev/null
+++ b/webrtc/modules/rtp_rtcp/source/rtcp_packet/receiver_report_unittest.cc
@@ -0,0 +1,145 @@
+/*
+ * 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/receiver_report.h"
+
+#include "testing/gtest/include/gtest/gtest.h"
+
+using webrtc::rtcp::RawPacket;
+using webrtc::rtcp::ReceiverReport;
+using webrtc::rtcp::ReportBlock;
+using webrtc::RTCPUtility::RtcpCommonHeader;
+using webrtc::RTCPUtility::RtcpParseCommonHeader;
+
+namespace webrtc {
+namespace {
+const uint32_t kSenderSsrc = 0x12345678;
+const uint32_t kRemoteSsrc = 0x23456789;
+const uint8_t kFractionLost = 55;
+const uint32_t kCumulativeLost = 0x111213;
+const uint32_t kExtHighestSeqNum = 0x22232425;
+const uint32_t kJitter = 0x33343536;
+const uint32_t kLastSr = 0x44454647;
+const uint32_t kDelayLastSr = 0x55565758;
+// Manually created ReceiverReport with one ReportBlock matching constants
+// above.
+// Having this block allows to test Create and Parse separately.
+const uint8_t kPacket[] = {0x81, 201, 0x00, 0x07, 0x12, 0x34, 0x56, 0x78,
+ 0x23, 0x45, 0x67, 0x89, 55, 0x11, 0x12, 0x13,
+ 0x22, 0x23, 0x24, 0x25, 0x33, 0x34, 0x35, 0x36,
+ 0x44, 0x45, 0x46, 0x47, 0x55, 0x56, 0x57, 0x58};
+const size_t kPacketLength = sizeof(kPacket);
+
+class RtcpPacketReceiverReportTest : public ::testing::Test {
+ protected:
+ void BuildPacket() { packet = rr.Build(); }
+ void ParsePacket() {
+ RtcpCommonHeader header;
+ EXPECT_TRUE(
+ RtcpParseCommonHeader(packet->Buffer(), packet->Length(), &header));
+ EXPECT_EQ(header.BlockSize(), packet->Length());
+ EXPECT_TRUE(parsed_.Parse(
+ header, packet->Buffer() + RtcpCommonHeader::kHeaderSizeBytes));
+ }
+
+ ReceiverReport rr;
+ rtc::scoped_ptr<RawPacket> packet;
+ const ReceiverReport& parsed() { return parsed_; }
+
+ private:
+ ReceiverReport parsed_;
+};
+
+TEST_F(RtcpPacketReceiverReportTest, Parse) {
+ RtcpCommonHeader header;
+ RtcpParseCommonHeader(kPacket, kPacketLength, &header);
+ EXPECT_TRUE(rr.Parse(header, kPacket + RtcpCommonHeader::kHeaderSizeBytes));
+ const ReceiverReport& parsed = rr;
+
+ EXPECT_EQ(kSenderSsrc, parsed.sender_ssrc());
+ EXPECT_EQ(1u, parsed.report_blocks().size());
+ const ReportBlock& rb = parsed.report_blocks().front();
+ EXPECT_EQ(kRemoteSsrc, rb.source_ssrc());
+ EXPECT_EQ(kFractionLost, rb.fraction_lost());
+ EXPECT_EQ(kCumulativeLost, rb.cumulative_lost());
+ EXPECT_EQ(kExtHighestSeqNum, rb.extended_high_seq_num());
+ EXPECT_EQ(kJitter, rb.jitter());
+ EXPECT_EQ(kLastSr, rb.last_sr());
+ EXPECT_EQ(kDelayLastSr, rb.delay_since_last_sr());
+}
+
+TEST_F(RtcpPacketReceiverReportTest, ParseFailsOnIncorrectSize) {
+ RtcpCommonHeader header;
+ RtcpParseCommonHeader(kPacket, kPacketLength, &header);
+ header.count_or_format++; // Damage the packet.
+ EXPECT_FALSE(rr.Parse(header, kPacket + RtcpCommonHeader::kHeaderSizeBytes));
+}
+
+TEST_F(RtcpPacketReceiverReportTest, Create) {
+ rr.From(kSenderSsrc);
+ ReportBlock rb;
+ rb.To(kRemoteSsrc);
+ rb.WithFractionLost(kFractionLost);
+ rb.WithCumulativeLost(kCumulativeLost);
+ rb.WithExtHighestSeqNum(kExtHighestSeqNum);
+ rb.WithJitter(kJitter);
+ rb.WithLastSr(kLastSr);
+ rb.WithDelayLastSr(kDelayLastSr);
+ rr.WithReportBlock(rb);
+
+ BuildPacket();
+
+ ASSERT_EQ(kPacketLength, packet->Length());
+ EXPECT_EQ(0, memcmp(kPacket, packet->Buffer(), kPacketLength));
+}
+
+TEST_F(RtcpPacketReceiverReportTest, WithoutReportBlocks) {
+ rr.From(kSenderSsrc);
+
+ BuildPacket();
+ ParsePacket();
+
+ EXPECT_EQ(kSenderSsrc, parsed().sender_ssrc());
+ EXPECT_EQ(0u, parsed().report_blocks().size());
+}
+
+TEST_F(RtcpPacketReceiverReportTest, WithTwoReportBlocks) {
+ ReportBlock rb1;
+ rb1.To(kRemoteSsrc);
+ ReportBlock rb2;
+ rb2.To(kRemoteSsrc + 1);
+
+ rr.From(kSenderSsrc);
+ EXPECT_TRUE(rr.WithReportBlock(rb1));
+ EXPECT_TRUE(rr.WithReportBlock(rb2));
+
+ BuildPacket();
+ ParsePacket();
+
+ 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(RtcpPacketReceiverReportTest, WithTooManyReportBlocks) {
+ rr.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(rr.WithReportBlock(rb));
+ }
+ rb.To(kRemoteSsrc + kMaxReportBlocks);
+ EXPECT_FALSE(rr.WithReportBlock(rb));
+}
+
+} // namespace
+} // namespace webrtc
diff --git a/webrtc/modules/rtp_rtcp/source/rtcp_packet/report_block.cc b/webrtc/modules/rtp_rtcp/source/rtcp_packet/report_block.cc
new file mode 100644
index 0000000000..4911dbf5b7
--- /dev/null
+++ b/webrtc/modules/rtp_rtcp/source/rtcp_packet/report_block.cc
@@ -0,0 +1,89 @@
+/*
+ * 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/report_block.h"
+
+#include "webrtc/base/checks.h"
+#include "webrtc/base/logging.h"
+#include "webrtc/modules/rtp_rtcp/source/byte_io.h"
+
+namespace webrtc {
+namespace rtcp {
+
+// From RFC 3550, RTP: A Transport Protocol for Real-Time Applications.
+//
+// RTCP report block (RFC 3550).
+//
+// 0 1 2 3
+// 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+// +=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+
+// 0 | SSRC_1 (SSRC of first source) |
+// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+// 4 | fraction lost | cumulative number of packets lost |
+// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+// 8 | extended highest sequence number received |
+// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+// 12 | interarrival jitter |
+// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+// 16 | last SR (LSR) |
+// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+// 20 | delay since last SR (DLSR) |
+// 24 +=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+
+ReportBlock::ReportBlock()
+ : source_ssrc_(0),
+ fraction_lost_(0),
+ cumulative_lost_(0),
+ extended_high_seq_num_(0),
+ jitter_(0),
+ last_sr_(0),
+ delay_since_last_sr_(0) {}
+
+bool ReportBlock::Parse(const uint8_t* buffer, size_t length) {
+ RTC_DCHECK(buffer != nullptr);
+ if (length < ReportBlock::kLength) {
+ LOG(LS_ERROR) << "Report Block should be 24 bytes long";
+ return false;
+ }
+
+ source_ssrc_ = ByteReader<uint32_t>::ReadBigEndian(&buffer[0]);
+ fraction_lost_ = buffer[4];
+ cumulative_lost_ = ByteReader<uint32_t, 3>::ReadBigEndian(&buffer[5]);
+ extended_high_seq_num_ = ByteReader<uint32_t>::ReadBigEndian(&buffer[8]);
+ jitter_ = ByteReader<uint32_t>::ReadBigEndian(&buffer[12]);
+ last_sr_ = ByteReader<uint32_t>::ReadBigEndian(&buffer[16]);
+ delay_since_last_sr_ = ByteReader<uint32_t>::ReadBigEndian(&buffer[20]);
+
+ return true;
+}
+
+void ReportBlock::Create(uint8_t* buffer) const {
+ // Runtime check should be done while setting cumulative_lost.
+ RTC_DCHECK_LT(cumulative_lost(), (1u << 24)); // Have only 3 bytes for it.
+
+ ByteWriter<uint32_t>::WriteBigEndian(&buffer[0], source_ssrc());
+ ByteWriter<uint8_t>::WriteBigEndian(&buffer[4], fraction_lost());
+ ByteWriter<uint32_t, 3>::WriteBigEndian(&buffer[5], cumulative_lost());
+ ByteWriter<uint32_t>::WriteBigEndian(&buffer[8], extended_high_seq_num());
+ ByteWriter<uint32_t>::WriteBigEndian(&buffer[12], jitter());
+ ByteWriter<uint32_t>::WriteBigEndian(&buffer[16], last_sr());
+ ByteWriter<uint32_t>::WriteBigEndian(&buffer[20], delay_since_last_sr());
+}
+
+bool ReportBlock::WithCumulativeLost(uint32_t cumulative_lost) {
+ if (cumulative_lost >= (1u << 24)) { // Have only 3 bytes to store it.
+ LOG(LS_WARNING) << "Cumulative lost is too big to fit into Report Block";
+ return false;
+ }
+ cumulative_lost_ = cumulative_lost;
+ return true;
+}
+
+} // namespace rtcp
+} // namespace webrtc
diff --git a/webrtc/modules/rtp_rtcp/source/rtcp_packet/report_block.h b/webrtc/modules/rtp_rtcp/source/rtcp_packet/report_block.h
new file mode 100644
index 0000000000..ef99e17297
--- /dev/null
+++ b/webrtc/modules/rtp_rtcp/source/rtcp_packet/report_block.h
@@ -0,0 +1,67 @@
+/*
+ * 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_REPORT_BLOCK_H_
+#define WEBRTC_MODULES_RTP_RTCP_SOURCE_RTCP_PACKET_REPORT_BLOCK_H_
+
+#include "webrtc/base/basictypes.h"
+
+namespace webrtc {
+namespace rtcp {
+
+class ReportBlock {
+ public:
+ static const size_t kLength = 24;
+
+ ReportBlock();
+ ~ReportBlock() {}
+
+ bool Parse(const uint8_t* buffer, size_t length);
+
+ // Fills buffer with the ReportBlock.
+ // Consumes ReportBlock::kLength bytes.
+ void Create(uint8_t* buffer) const;
+
+ void To(uint32_t ssrc) { source_ssrc_ = ssrc; }
+ void WithFractionLost(uint8_t fraction_lost) {
+ fraction_lost_ = fraction_lost;
+ }
+ bool WithCumulativeLost(uint32_t cumulative_lost);
+ void WithExtHighestSeqNum(uint32_t ext_highest_seq_num) {
+ extended_high_seq_num_ = ext_highest_seq_num;
+ }
+ void WithJitter(uint32_t jitter) { jitter_ = jitter; }
+ void WithLastSr(uint32_t last_sr) { last_sr_ = last_sr; }
+ void WithDelayLastSr(uint32_t delay_last_sr) {
+ delay_since_last_sr_ = delay_last_sr;
+ }
+
+ uint32_t source_ssrc() const { return source_ssrc_; }
+ uint8_t fraction_lost() const { return fraction_lost_; }
+ uint32_t cumulative_lost() const { return cumulative_lost_; }
+ uint32_t extended_high_seq_num() const { return extended_high_seq_num_; }
+ uint32_t jitter() const { return jitter_; }
+ uint32_t last_sr() const { return last_sr_; }
+ uint32_t delay_since_last_sr() const { return delay_since_last_sr_; }
+
+ private:
+ uint32_t source_ssrc_;
+ uint8_t fraction_lost_;
+ uint32_t cumulative_lost_;
+ uint32_t extended_high_seq_num_;
+ uint32_t jitter_;
+ uint32_t last_sr_;
+ uint32_t delay_since_last_sr_;
+};
+
+} // namespace rtcp
+} // namespace webrtc
+#endif // WEBRTC_MODULES_RTP_RTCP_SOURCE_RTCP_PACKET_REPORT_BLOCK_H_
diff --git a/webrtc/modules/rtp_rtcp/source/rtcp_packet/report_block_unittest.cc b/webrtc/modules/rtp_rtcp/source/rtcp_packet/report_block_unittest.cc
new file mode 100644
index 0000000000..85bbb404a4
--- /dev/null
+++ b/webrtc/modules/rtp_rtcp/source/rtcp_packet/report_block_unittest.cc
@@ -0,0 +1,86 @@
+/*
+ * 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/report_block.h"
+
+#include <limits>
+
+#include "testing/gtest/include/gtest/gtest.h"
+#include "webrtc/base/random.h"
+
+using webrtc::rtcp::ReportBlock;
+
+namespace webrtc {
+namespace {
+
+const uint32_t kRemoteSsrc = 0x23456789;
+const uint8_t kFractionLost = 55;
+// Use values that are streamed differently LE and BE.
+const uint32_t kCumulativeLost = 0x111213;
+const uint32_t kExtHighestSeqNum = 0x22232425;
+const uint32_t kJitter = 0x33343536;
+const uint32_t kLastSr = 0x44454647;
+const uint32_t kDelayLastSr = 0x55565758;
+const size_t kBufferLength = ReportBlock::kLength;
+
+TEST(RtcpPacketReportBlockTest, ParseChecksLength) {
+ uint8_t buffer[kBufferLength];
+ memset(buffer, 0, sizeof(buffer));
+
+ ReportBlock rb;
+ EXPECT_FALSE(rb.Parse(buffer, kBufferLength - 1));
+ EXPECT_TRUE(rb.Parse(buffer, kBufferLength));
+}
+
+TEST(RtcpPacketReportBlockTest, ParseAnyData) {
+ uint8_t buffer[kBufferLength];
+ // Fill buffer with semi-random data.
+ Random generator(0x256F8A285EC829ull);
+ for (size_t i = 0; i < kBufferLength; ++i)
+ buffer[i] = static_cast<uint8_t>(generator.Rand(0, 0xff));
+
+ ReportBlock rb;
+ EXPECT_TRUE(rb.Parse(buffer, kBufferLength));
+}
+
+TEST(RtcpPacketReportBlockTest, ParseMatchCreate) {
+ ReportBlock rb;
+ rb.To(kRemoteSsrc);
+ rb.WithFractionLost(kFractionLost);
+ rb.WithCumulativeLost(kCumulativeLost);
+ rb.WithExtHighestSeqNum(kExtHighestSeqNum);
+ rb.WithJitter(kJitter);
+ rb.WithLastSr(kLastSr);
+ rb.WithDelayLastSr(kDelayLastSr);
+
+ uint8_t buffer[kBufferLength];
+ rb.Create(buffer);
+
+ ReportBlock parsed;
+ EXPECT_TRUE(parsed.Parse(buffer, kBufferLength));
+
+ EXPECT_EQ(kRemoteSsrc, parsed.source_ssrc());
+ EXPECT_EQ(kFractionLost, parsed.fraction_lost());
+ EXPECT_EQ(kCumulativeLost, parsed.cumulative_lost());
+ EXPECT_EQ(kExtHighestSeqNum, parsed.extended_high_seq_num());
+ EXPECT_EQ(kJitter, parsed.jitter());
+ EXPECT_EQ(kLastSr, parsed.last_sr());
+ EXPECT_EQ(kDelayLastSr, parsed.delay_since_last_sr());
+}
+
+TEST(RtcpPacketReportBlockTest, ValidateCumulativeLost) {
+ const uint32_t kMaxCumulativeLost = 0xffffff;
+ ReportBlock rb;
+ EXPECT_FALSE(rb.WithCumulativeLost(kMaxCumulativeLost + 1));
+ EXPECT_TRUE(rb.WithCumulativeLost(kMaxCumulativeLost));
+}
+
+} // namespace
+} // namespace webrtc
diff --git a/webrtc/modules/rtp_rtcp/source/rtcp_packet/rrtr.cc b/webrtc/modules/rtp_rtcp/source/rtcp_packet/rrtr.cc
new file mode 100644
index 0000000000..db4ae67326
--- /dev/null
+++ b/webrtc/modules/rtp_rtcp/source/rtcp_packet/rrtr.cc
@@ -0,0 +1,49 @@
+/*
+ * 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/rrtr.h"
+
+#include "webrtc/base/checks.h"
+#include "webrtc/modules/rtp_rtcp/source/byte_io.h"
+
+namespace webrtc {
+namespace rtcp {
+// 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 Rrtr::Parse(const uint8_t* buffer) {
+ RTC_DCHECK(buffer[0] == kBlockType);
+ // reserved = buffer[1];
+ RTC_DCHECK(ByteReader<uint16_t>::ReadBigEndian(&buffer[2]) == kBlockLength);
+ uint32_t seconds = ByteReader<uint32_t>::ReadBigEndian(&buffer[4]);
+ uint32_t fraction = ByteReader<uint32_t>::ReadBigEndian(&buffer[8]);
+ ntp_.Set(seconds, fraction);
+}
+
+void Rrtr::Create(uint8_t* buffer) const {
+ const uint8_t kReserved = 0;
+ buffer[0] = kBlockType;
+ buffer[1] = kReserved;
+ ByteWriter<uint16_t>::WriteBigEndian(&buffer[2], kBlockLength);
+ ByteWriter<uint32_t>::WriteBigEndian(&buffer[4], ntp_.seconds());
+ ByteWriter<uint32_t>::WriteBigEndian(&buffer[8], ntp_.fractions());
+}
+
+} // namespace rtcp
+} // namespace webrtc
diff --git a/webrtc/modules/rtp_rtcp/source/rtcp_packet/rrtr.h b/webrtc/modules/rtp_rtcp/source/rtcp_packet/rrtr.h
new file mode 100644
index 0000000000..3354f61df6
--- /dev/null
+++ b/webrtc/modules/rtp_rtcp/source/rtcp_packet/rrtr.h
@@ -0,0 +1,49 @@
+/*
+ * 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_RRTR_H_
+#define WEBRTC_MODULES_RTP_RTCP_SOURCE_RTCP_PACKET_RRTR_H_
+
+#include "webrtc/base/basictypes.h"
+#include "webrtc/system_wrappers/include/ntp_time.h"
+
+namespace webrtc {
+namespace rtcp {
+
+class Rrtr {
+ public:
+ static const uint8_t kBlockType = 4;
+ static const uint16_t kBlockLength = 2;
+ static const size_t kLength = 4 * (kBlockLength + 1); // 12
+
+ Rrtr() {}
+ Rrtr(const Rrtr&) = default;
+ ~Rrtr() {}
+
+ Rrtr& operator=(const Rrtr&) = default;
+
+ void Parse(const uint8_t* buffer);
+
+ // Fills buffer with the Rrtr.
+ // Consumes Rrtr::kLength bytes.
+ void Create(uint8_t* buffer) const;
+
+ void WithNtp(const NtpTime& ntp) { ntp_ = ntp; }
+
+ NtpTime ntp() const { return ntp_; }
+
+ private:
+ NtpTime ntp_;
+};
+
+} // namespace rtcp
+} // namespace webrtc
+#endif // WEBRTC_MODULES_RTP_RTCP_SOURCE_RTCP_PACKET_RRTR_H_
diff --git a/webrtc/modules/rtp_rtcp/source/rtcp_packet/rrtr_unittest.cc b/webrtc/modules/rtp_rtcp/source/rtcp_packet/rrtr_unittest.cc
new file mode 100644
index 0000000000..6536e06186
--- /dev/null
+++ b/webrtc/modules/rtp_rtcp/source/rtcp_packet/rrtr_unittest.cc
@@ -0,0 +1,51 @@
+/*
+ * 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/rrtr.h"
+
+#include "testing/gtest/include/gtest/gtest.h"
+
+using webrtc::rtcp::Rrtr;
+
+namespace webrtc {
+namespace {
+
+const uint32_t kNtpSec = 0x12345678;
+const uint32_t kNtpFrac = 0x23456789;
+const uint8_t kBlock[] = {0x04, 0x00, 0x00, 0x02,
+ 0x12, 0x34, 0x56, 0x78,
+ 0x23, 0x45, 0x67, 0x89};
+const size_t kBlockSizeBytes = sizeof(kBlock);
+static_assert(
+ kBlockSizeBytes == Rrtr::kLength,
+ "Size of manually created Rrtr block should match class constant");
+
+TEST(RtcpPacketRrtrTest, Create) {
+ uint8_t buffer[Rrtr::kLength];
+ Rrtr rrtr;
+ rrtr.WithNtp(NtpTime(kNtpSec, kNtpFrac));
+
+ rrtr.Create(buffer);
+ EXPECT_EQ(0, memcmp(buffer, kBlock, kBlockSizeBytes));
+}
+
+TEST(RtcpPacketRrtrTest, Parse) {
+ Rrtr read_rrtr;
+ read_rrtr.Parse(kBlock);
+
+ // Run checks on const object to ensure all accessors have const modifier.
+ const Rrtr& parsed = read_rrtr;
+
+ EXPECT_EQ(kNtpSec, parsed.ntp().seconds());
+ EXPECT_EQ(kNtpFrac, parsed.ntp().fractions());
+}
+
+} // namespace
+} // namespace webrtc
diff --git a/webrtc/modules/rtp_rtcp/source/rtcp_packet/rtpfb.cc b/webrtc/modules/rtp_rtcp/source/rtcp_packet/rtpfb.cc
new file mode 100644
index 0000000000..b5571d45a3
--- /dev/null
+++ b/webrtc/modules/rtp_rtcp/source/rtcp_packet/rtpfb.cc
@@ -0,0 +1,45 @@
+/*
+ * 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/rtpfb.h"
+
+#include "webrtc/modules/rtp_rtcp/source/byte_io.h"
+
+namespace webrtc {
+namespace rtcp {
+
+// RFC 4585, Section 6.1: Feedback format.
+//
+// Common packet format:
+//
+// 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 | PT | length |
+// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+// 0 | SSRC of packet sender |
+// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+// 4 | SSRC of media source |
+// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+// : Feedback Control Information (FCI) :
+// : :
+
+void Rtpfb::ParseCommonFeedback(const uint8_t* payload) {
+ sender_ssrc_ = ByteReader<uint32_t>::ReadBigEndian(&payload[0]);
+ media_ssrc_ = ByteReader<uint32_t>::ReadBigEndian(&payload[4]);
+}
+
+void Rtpfb::CreateCommonFeedback(uint8_t* payload) const {
+ ByteWriter<uint32_t>::WriteBigEndian(&payload[0], sender_ssrc_);
+ ByteWriter<uint32_t>::WriteBigEndian(&payload[4], media_ssrc_);
+}
+
+} // namespace rtcp
+} // namespace webrtc
diff --git a/webrtc/modules/rtp_rtcp/source/rtcp_packet/rtpfb.h b/webrtc/modules/rtp_rtcp/source/rtcp_packet/rtpfb.h
new file mode 100644
index 0000000000..801aa085c4
--- /dev/null
+++ b/webrtc/modules/rtp_rtcp/source/rtcp_packet/rtpfb.h
@@ -0,0 +1,48 @@
+/*
+ * 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_RTPFB_H_
+#define WEBRTC_MODULES_RTP_RTCP_SOURCE_RTCP_PACKET_RTPFB_H_
+
+#include "webrtc/base/basictypes.h"
+#include "webrtc/modules/rtp_rtcp/source/rtcp_packet.h"
+
+namespace webrtc {
+namespace rtcp {
+
+// RTPFB: Transport layer feedback message.
+// RFC4585, Section 6.2
+class Rtpfb : public RtcpPacket {
+ public:
+ static const uint8_t kPacketType = 205;
+
+ Rtpfb() : sender_ssrc_(0), media_ssrc_(0) {}
+ virtual ~Rtpfb() {}
+
+ void From(uint32_t ssrc) { sender_ssrc_ = ssrc; }
+ void To(uint32_t ssrc) { media_ssrc_ = ssrc; }
+
+ uint32_t sender_ssrc() const { return sender_ssrc_; }
+ uint32_t media_ssrc() const { return media_ssrc_; }
+
+ protected:
+ static const size_t kCommonFeedbackLength = 8;
+ void ParseCommonFeedback(const uint8_t* payload);
+ void CreateCommonFeedback(uint8_t* payload) const;
+
+ private:
+ uint32_t sender_ssrc_;
+ uint32_t media_ssrc_;
+};
+
+} // namespace rtcp
+} // namespace webrtc
+#endif // WEBRTC_MODULES_RTP_RTCP_SOURCE_RTCP_PACKET_RTPFB_H_
diff --git a/webrtc/modules/rtp_rtcp/source/rtcp_packet/sli.cc b/webrtc/modules/rtp_rtcp/source/rtcp_packet/sli.cc
new file mode 100644
index 0000000000..829f3a9db9
--- /dev/null
+++ b/webrtc/modules/rtp_rtcp/source/rtcp_packet/sli.cc
@@ -0,0 +1,108 @@
+/*
+ * 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/sli.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 {
+// RFC 4585: Feedback format.
+//
+// Common packet format:
+//
+// 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 | PT | length |
+// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+// | SSRC of packet sender |
+// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+// | SSRC of media source |
+// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+// : Feedback Control Information (FCI) :
+// : :
+//
+// Slice loss indication (SLI) (RFC 4585).
+// FCI:
+// 0 1 2 3
+// 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+// | First | Number | PictureID |
+// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+Sli::Macroblocks::Macroblocks(uint8_t picture_id,
+ uint16_t first,
+ uint16_t number) {
+ RTC_DCHECK_LE(first, 0x1fff);
+ RTC_DCHECK_LE(number, 0x1fff);
+ RTC_DCHECK_LE(picture_id, 0x3f);
+ item_ = (first << 19) | (number << 6) | picture_id;
+}
+
+void Sli::Macroblocks::Parse(const uint8_t* buffer) {
+ item_ = ByteReader<uint32_t>::ReadBigEndian(buffer);
+}
+
+void Sli::Macroblocks::Create(uint8_t* buffer) const {
+ ByteWriter<uint32_t>::WriteBigEndian(buffer, item_);
+}
+
+bool Sli::Parse(const RtcpCommonHeader& header, const uint8_t* payload) {
+ RTC_DCHECK(header.packet_type == kPacketType);
+ RTC_DCHECK(header.count_or_format == kFeedbackMessageType);
+
+ if (header.payload_size_bytes <
+ kCommonFeedbackLength + Macroblocks::kLength) {
+ LOG(LS_WARNING) << "Packet is too small to be a valid SLI packet";
+ return false;
+ }
+
+ size_t number_of_items =
+ (header.payload_size_bytes - kCommonFeedbackLength) /
+ Macroblocks::kLength;
+
+ ParseCommonFeedback(payload);
+ items_.resize(number_of_items);
+
+ const uint8_t* next_item = payload + kCommonFeedbackLength;
+ for (Macroblocks& item : items_) {
+ item.Parse(next_item);
+ next_item += Macroblocks::kLength;
+ }
+
+ return true;
+}
+
+bool Sli::Create(uint8_t* packet,
+ size_t* index,
+ size_t max_length,
+ RtcpPacket::PacketReadyCallback* callback) const {
+ RTC_DCHECK(!items_.empty());
+ while (*index + BlockLength() > max_length) {
+ if (!OnBufferFull(packet, index, callback))
+ return false;
+ }
+ CreateHeader(kFeedbackMessageType, kPacketType, HeaderLength(), packet,
+ index);
+ CreateCommonFeedback(packet + *index);
+ *index += kCommonFeedbackLength;
+ for (const Macroblocks& item : items_) {
+ item.Create(packet + *index);
+ *index += Macroblocks::kLength;
+ }
+ return true;
+}
+
+} // namespace rtcp
+} // namespace webrtc
diff --git a/webrtc/modules/rtp_rtcp/source/rtcp_packet/sli.h b/webrtc/modules/rtp_rtcp/source/rtcp_packet/sli.h
new file mode 100644
index 0000000000..5d9e6c93e9
--- /dev/null
+++ b/webrtc/modules/rtp_rtcp/source/rtcp_packet/sli.h
@@ -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.
+ *
+ */
+
+#ifndef WEBRTC_MODULES_RTP_RTCP_SOURCE_RTCP_PACKET_SLI_H_
+#define WEBRTC_MODULES_RTP_RTCP_SOURCE_RTCP_PACKET_SLI_H_
+
+#include <vector>
+
+#include "webrtc/base/basictypes.h"
+#include "webrtc/modules/rtp_rtcp/source/rtcp_packet/psfb.h"
+#include "webrtc/modules/rtp_rtcp/source/rtcp_utility.h"
+
+namespace webrtc {
+namespace rtcp {
+
+// Slice loss indication (SLI) (RFC 4585).
+class Sli : public Psfb {
+ public:
+ static const uint8_t kFeedbackMessageType = 2;
+ class Macroblocks {
+ public:
+ static const size_t kLength = 4;
+ Macroblocks() : item_(0) {}
+ Macroblocks(uint8_t picture_id, uint16_t first, uint16_t number);
+ ~Macroblocks() {}
+
+ void Parse(const uint8_t* buffer);
+ void Create(uint8_t* buffer) const;
+
+ uint16_t first() const { return item_ >> 19; }
+ uint16_t number() const { return (item_ >> 6) & 0x1fff; }
+ uint8_t picture_id() const { return (item_ & 0x3f); }
+
+ private:
+ uint32_t item_;
+ };
+
+ Sli() {}
+ virtual ~Sli() {}
+
+ // 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 WithPictureId(uint8_t picture_id,
+ uint16_t first_macroblock = 0,
+ uint16_t number_macroblocks = 0x1fff) {
+ items_.push_back(
+ Macroblocks(picture_id, first_macroblock, number_macroblocks));
+ }
+
+ const std::vector<Macroblocks>& macroblocks() const { return items_; }
+
+ protected:
+ bool Create(uint8_t* packet,
+ size_t* index,
+ size_t max_length,
+ RtcpPacket::PacketReadyCallback* callback) const override;
+
+ private:
+ size_t BlockLength() const override {
+ return RtcpPacket::kHeaderLength + Psfb::kCommonFeedbackLength +
+ items_.size() * Macroblocks::kLength;
+ }
+
+ std::vector<Macroblocks> items_;
+
+ RTC_DISALLOW_COPY_AND_ASSIGN(Sli);
+};
+
+} // namespace rtcp
+} // namespace webrtc
+#endif // WEBRTC_MODULES_RTP_RTCP_SOURCE_RTCP_PACKET_SLI_H_
diff --git a/webrtc/modules/rtp_rtcp/source/rtcp_packet/sli_unittest.cc b/webrtc/modules/rtp_rtcp/source/rtcp_packet/sli_unittest.cc
new file mode 100644
index 0000000000..c2be16846b
--- /dev/null
+++ b/webrtc/modules/rtp_rtcp/source/rtcp_packet/sli_unittest.cc
@@ -0,0 +1,91 @@
+/*
+ * 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/sli.h"
+
+#include "testing/gmock/include/gmock/gmock.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+using testing::ElementsAreArray;
+using testing::make_tuple;
+using webrtc::rtcp::RawPacket;
+using webrtc::rtcp::Sli;
+using webrtc::RTCPUtility::RtcpCommonHeader;
+using webrtc::RTCPUtility::RtcpParseCommonHeader;
+
+namespace webrtc {
+namespace {
+
+const uint32_t kSenderSsrc = 0x12345678;
+const uint32_t kRemoteSsrc = 0x23456789;
+
+const uint8_t kPictureId = 0x3f;
+const uint16_t kFirstMb = 0x1e61;
+const uint16_t kNumberOfMb = 0x1a0a;
+const uint32_t kSliItem = (static_cast<uint32_t>(kFirstMb) << 19) |
+ (static_cast<uint32_t>(kNumberOfMb) << 6) |
+ static_cast<uint32_t>(kPictureId);
+
+// Manually created Sli packet matching constants above.
+const uint8_t kPacket[] = {0x82, 206, 0x00, 0x03,
+ 0x12, 0x34, 0x56, 0x78,
+ 0x23, 0x45, 0x67, 0x89,
+ (kSliItem >> 24) & 0xff,
+ (kSliItem >> 16) & 0xff,
+ (kSliItem >> 8) & 0xff,
+ kSliItem & 0xff};
+const size_t kPacketLength = sizeof(kPacket);
+
+bool ParseSli(const uint8_t* buffer, size_t length, Sli* sli) {
+ RtcpCommonHeader header;
+ EXPECT_TRUE(RtcpParseCommonHeader(buffer, length, &header));
+ EXPECT_EQ(length, header.BlockSize());
+ return sli->Parse(header, buffer + RtcpCommonHeader::kHeaderSizeBytes);
+}
+
+TEST(RtcpPacketSliTest, Create) {
+ Sli sli;
+ sli.From(kSenderSsrc);
+ sli.To(kRemoteSsrc);
+ sli.WithPictureId(kPictureId, kFirstMb, kNumberOfMb);
+
+ rtc::scoped_ptr<RawPacket> packet(sli.Build());
+
+ EXPECT_THAT(make_tuple(packet->Buffer(), packet->Length()),
+ ElementsAreArray(kPacket));
+}
+
+TEST(RtcpPacketSliTest, Parse) {
+ Sli mutable_parsed;
+ EXPECT_TRUE(ParseSli(kPacket, kPacketLength, &mutable_parsed));
+ const Sli& parsed = mutable_parsed; // Read values from constant object.
+
+ EXPECT_EQ(kSenderSsrc, parsed.sender_ssrc());
+ EXPECT_EQ(kRemoteSsrc, parsed.media_ssrc());
+ EXPECT_EQ(1u, parsed.macroblocks().size());
+ EXPECT_EQ(kFirstMb, parsed.macroblocks()[0].first());
+ EXPECT_EQ(kNumberOfMb, parsed.macroblocks()[0].number());
+ EXPECT_EQ(kPictureId, parsed.macroblocks()[0].picture_id());
+}
+
+TEST(RtcpPacketSliTest, ParseFailsOnTooSmallPacket) {
+ Sli sli;
+ sli.From(kSenderSsrc);
+ sli.To(kRemoteSsrc);
+ sli.WithPictureId(kPictureId, kFirstMb, kNumberOfMb);
+
+ rtc::scoped_ptr<RawPacket> packet(sli.Build());
+ packet->MutableBuffer()[3]--; // Decrease size by 1 word (4 bytes).
+
+ EXPECT_FALSE(ParseSli(packet->Buffer(), packet->Length() - 4, &sli));
+}
+
+} // namespace
+} // namespace webrtc
diff --git a/webrtc/modules/rtp_rtcp/source/rtcp_packet/tmmbn.cc b/webrtc/modules/rtp_rtcp/source/rtcp_packet/tmmbn.cc
new file mode 100644
index 0000000000..fd0219cf82
--- /dev/null
+++ b/webrtc/modules/rtp_rtcp/source/rtcp_packet/tmmbn.cc
@@ -0,0 +1,119 @@
+/*
+ * 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/tmmbn.h"
+
+#include "webrtc/base/logging.h"
+#include "webrtc/modules/rtp_rtcp/source/byte_io.h"
+
+using webrtc::RTCPUtility::PT_RTPFB;
+using webrtc::RTCPUtility::RTCPPacketRTPFBTMMBN;
+using webrtc::RTCPUtility::RTCPPacketRTPFBTMMBRItem;
+
+namespace webrtc {
+namespace rtcp {
+namespace {
+const uint32_t kUnusedMediaSourceSsrc0 = 0;
+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;
+}
+
+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);
+}
+
+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 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,
+ uint8_t* buffer,
+ size_t* 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);
+ }
+}
+} // namespace
+
+bool 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 false;
+ }
+ RTCPPacketRTPFBTMMBRItem tmmbn_item;
+ tmmbn_item.SSRC = ssrc;
+ tmmbn_item.MaxTotalMediaBitRate = bitrate_kbps;
+ tmmbn_item.MeasuredOverhead = overhead;
+ tmmbn_items_.push_back(tmmbn_item);
+ return true;
+}
+
+bool Tmmbn::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 uint8_t kFmt = 4;
+ CreateHeader(kFmt, PT_RTPFB, HeaderLength(), packet, index);
+ CreateTmmbn(tmmbn_, tmmbn_items_, packet, index);
+ return true;
+}
+
+} // namespace rtcp
+} // namespace webrtc
diff --git a/webrtc/modules/rtp_rtcp/source/rtcp_packet/tmmbn.h b/webrtc/modules/rtp_rtcp/source/rtcp_packet/tmmbn.h
new file mode 100644
index 0000000000..82bf9dd9e9
--- /dev/null
+++ b/webrtc/modules/rtp_rtcp/source/rtcp_packet/tmmbn.h
@@ -0,0 +1,60 @@
+/*
+ * 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_TMMBN_H_
+#define WEBRTC_MODULES_RTP_RTCP_SOURCE_RTCP_PACKET_TMMBN_H_
+
+#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 {
+
+// Temporary Maximum Media Stream Bit Rate Notification (TMMBN) (RFC 5104).
+class Tmmbn : public RtcpPacket {
+ public:
+ Tmmbn() : RtcpPacket() {
+ memset(&tmmbn_, 0, sizeof(tmmbn_));
+ }
+
+ virtual ~Tmmbn() {}
+
+ void From(uint32_t ssrc) {
+ tmmbn_.SenderSSRC = ssrc;
+ }
+ // Max 50 TMMBR can be added per TMMBN.
+ bool WithTmmbr(uint32_t ssrc, uint32_t bitrate_kbps, uint16_t overhead);
+
+ protected:
+ bool Create(uint8_t* packet,
+ size_t* index,
+ size_t max_length,
+ RtcpPacket::PacketReadyCallback* callback) const override;
+
+ private:
+ static const int 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_;
+
+ RTC_DISALLOW_COPY_AND_ASSIGN(Tmmbn);
+};
+
+} // namespace rtcp
+} // namespace webrtc
+#endif // WEBRTC_MODULES_RTP_RTCP_SOURCE_RTCP_PACKET_TMMBN_H_
diff --git a/webrtc/modules/rtp_rtcp/source/rtcp_packet/tmmbn_unittest.cc b/webrtc/modules/rtp_rtcp/source/rtcp_packet/tmmbn_unittest.cc
new file mode 100644
index 0000000000..32d64a97b4
--- /dev/null
+++ b/webrtc/modules/rtp_rtcp/source/rtcp_packet/tmmbn_unittest.cc
@@ -0,0 +1,84 @@
+/*
+ * 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/tmmbn.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::Tmmbn;
+using webrtc::test::RtcpPacketParser;
+
+namespace webrtc {
+const uint32_t kSenderSsrc = 0x12345678;
+const uint32_t kRemoteSsrc = 0x23456789;
+
+TEST(RtcpPacketTest, TmmbnWithNoItem) {
+ Tmmbn tmmbn;
+ tmmbn.From(kSenderSsrc);
+
+ rtc::scoped_ptr<RawPacket> packet(tmmbn.Build());
+ RtcpPacketParser parser;
+ parser.Parse(packet->Buffer(), packet->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);
+ EXPECT_TRUE(tmmbn.WithTmmbr(kRemoteSsrc, 312, 60));
+
+ rtc::scoped_ptr<RawPacket> packet(tmmbn.Build());
+ RtcpPacketParser parser;
+ parser.Parse(packet->Buffer(), packet->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);
+ EXPECT_TRUE(tmmbn.WithTmmbr(kRemoteSsrc, 312, 60));
+ EXPECT_TRUE(tmmbn.WithTmmbr(kRemoteSsrc + 1, 1288, 40));
+
+ rtc::scoped_ptr<RawPacket> packet(tmmbn.Build());
+ RtcpPacketParser parser;
+ parser.Parse(packet->Buffer(), packet->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, TmmbnWithTooManyItems) {
+ Tmmbn tmmbn;
+ tmmbn.From(kSenderSsrc);
+ const int kMaxTmmbrItems = 50;
+ for (int i = 0; i < kMaxTmmbrItems; ++i)
+ EXPECT_TRUE(tmmbn.WithTmmbr(kRemoteSsrc + i, 312, 60));
+
+ EXPECT_FALSE(tmmbn.WithTmmbr(kRemoteSsrc + kMaxTmmbrItems, 312, 60));
+}
+
+} // namespace webrtc
diff --git a/webrtc/modules/rtp_rtcp/source/rtcp_packet/tmmbr.cc b/webrtc/modules/rtp_rtcp/source/rtcp_packet/tmmbr.cc
new file mode 100644
index 0000000000..4df167de79
--- /dev/null
+++ b/webrtc/modules/rtp_rtcp/source/rtcp_packet/tmmbr.cc
@@ -0,0 +1,105 @@
+/*
+ * 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/tmmbr.h"
+
+#include "webrtc/base/logging.h"
+#include "webrtc/modules/rtp_rtcp/source/byte_io.h"
+
+using webrtc::RTCPUtility::PT_RTPFB;
+using webrtc::RTCPUtility::RTCPPacketRTPFBTMMBR;
+using webrtc::RTCPUtility::RTCPPacketRTPFBTMMBRItem;
+
+namespace webrtc {
+namespace rtcp {
+namespace {
+const uint32_t kUnusedMediaSourceSsrc0 = 0;
+
+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;
+}
+
+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);
+}
+
+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,
+ uint8_t* buffer,
+ size_t* pos) {
+ AssignUWord32(buffer, pos, tmmbr.SenderSSRC);
+ AssignUWord32(buffer, pos, kUnusedMediaSourceSsrc0);
+ CreateTmmbrItem(tmmbr_item, buffer, pos);
+}
+} // namespace
+
+bool Tmmbr::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 uint8_t kFmt = 3;
+ CreateHeader(kFmt, PT_RTPFB, HeaderLength(), packet, index);
+ CreateTmmbr(tmmbr_, tmmbr_item_, packet, index);
+ return true;
+}
+
+} // namespace rtcp
+} // namespace webrtc
diff --git a/webrtc/modules/rtp_rtcp/source/rtcp_packet/tmmbr.h b/webrtc/modules/rtp_rtcp/source/rtcp_packet/tmmbr.h
new file mode 100644
index 0000000000..84a4180ad3
--- /dev/null
+++ b/webrtc/modules/rtp_rtcp/source/rtcp_packet/tmmbr.h
@@ -0,0 +1,64 @@
+/*
+ * 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_TMMBR_H_
+#define WEBRTC_MODULES_RTP_RTCP_SOURCE_RTCP_PACKET_TMMBR_H_
+
+#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 {
+// Temporary Maximum Media Stream Bit Rate Request (TMMBR) (RFC 5104).
+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:
+ bool Create(uint8_t* packet,
+ size_t* index,
+ size_t max_length,
+ RtcpPacket::PacketReadyCallback* callback) const override;
+
+ private:
+ size_t BlockLength() const {
+ const size_t kFciLen = 8;
+ return kCommonFbFmtLength + kFciLen;
+ }
+
+ RTCPUtility::RTCPPacketRTPFBTMMBR tmmbr_;
+ RTCPUtility::RTCPPacketRTPFBTMMBRItem tmmbr_item_;
+
+ RTC_DISALLOW_COPY_AND_ASSIGN(Tmmbr);
+};
+} // namespace rtcp
+} // namespace webrtc
+#endif // WEBRTC_MODULES_RTP_RTCP_SOURCE_RTCP_PACKET_TMMBR_H_
diff --git a/webrtc/modules/rtp_rtcp/source/rtcp_packet/tmmbr_unittest.cc b/webrtc/modules/rtp_rtcp/source/rtcp_packet/tmmbr_unittest.cc
new file mode 100644
index 0000000000..6d71caa251
--- /dev/null
+++ b/webrtc/modules/rtp_rtcp/source/rtcp_packet/tmmbr_unittest.cc
@@ -0,0 +1,43 @@
+/*
+ * 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/tmmbr.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::Tmmbr;
+using webrtc::test::RtcpPacketParser;
+
+namespace webrtc {
+const uint32_t kSenderSsrc = 0x12345678;
+const uint32_t kRemoteSsrc = 0x23456789;
+
+TEST(RtcpPacketTest, Tmmbr) {
+ Tmmbr tmmbr;
+ tmmbr.From(kSenderSsrc);
+ tmmbr.To(kRemoteSsrc);
+ tmmbr.WithBitrateKbps(312);
+ tmmbr.WithOverhead(60);
+
+ rtc::scoped_ptr<RawPacket> packet(tmmbr.Build());
+ RtcpPacketParser parser;
+ parser.Parse(packet->Buffer(), packet->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());
+}
+
+} // namespace webrtc
diff --git a/webrtc/modules/rtp_rtcp/source/rtcp_packet/transport_feedback.h b/webrtc/modules/rtp_rtcp/source/rtcp_packet/transport_feedback.h
index 4cc1f38479..ad6fd166f2 100644
--- a/webrtc/modules/rtp_rtcp/source/rtcp_packet/transport_feedback.h
+++ b/webrtc/modules/rtp_rtcp/source/rtcp_packet/transport_feedback.h
@@ -15,7 +15,7 @@
#include <vector>
#include "webrtc/base/constructormagic.h"
-#include "webrtc/modules/interface/module_common_types.h"
+#include "webrtc/modules/include/module_common_types.h"
#include "webrtc/modules/rtp_rtcp/source/rtcp_packet.h"
namespace webrtc {
diff --git a/webrtc/modules/rtp_rtcp/source/rtcp_packet/voip_metric.cc b/webrtc/modules/rtp_rtcp/source/rtcp_packet/voip_metric.cc
new file mode 100644
index 0000000000..a79d48e1ca
--- /dev/null
+++ b/webrtc/modules/rtp_rtcp/source/rtcp_packet/voip_metric.cc
@@ -0,0 +1,107 @@
+/*
+ * 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/voip_metric.h"
+
+#include "webrtc/base/checks.h"
+#include "webrtc/modules/rtp_rtcp/source/byte_io.h"
+
+namespace webrtc {
+namespace rtcp {
+// 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
+// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+// 0 | BT=7 | reserved | block length = 8 |
+// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+// 4 | SSRC of source |
+// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+// 8 | loss rate | discard rate | burst density | gap density |
+// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+// 12 | burst duration | gap duration |
+// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+// 16 | round trip delay | end system delay |
+// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+// 20 | signal level | noise level | RERL | Gmin |
+// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+// 24 | R factor | ext. R factor | MOS-LQ | MOS-CQ |
+// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+// 28 | RX config | reserved | JB nominal |
+// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+// 32 | JB maximum | JB abs max |
+// 36 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+VoipMetric::VoipMetric() : ssrc_(0) {
+ memset(&voip_metric_, 0, sizeof(voip_metric_));
+}
+
+void VoipMetric::Parse(const uint8_t* buffer) {
+ RTC_DCHECK(buffer[0] == kBlockType);
+ // reserved = buffer[1];
+ RTC_DCHECK(ByteReader<uint16_t>::ReadBigEndian(&buffer[2]) == kBlockLength);
+ ssrc_ = ByteReader<uint32_t>::ReadBigEndian(&buffer[4]);
+ voip_metric_.lossRate = buffer[8];
+ voip_metric_.discardRate = buffer[9];
+ voip_metric_.burstDensity = buffer[10];
+ voip_metric_.gapDensity = buffer[11];
+ voip_metric_.burstDuration = ByteReader<uint16_t>::ReadBigEndian(&buffer[12]);
+ voip_metric_.gapDuration = ByteReader<uint16_t>::ReadBigEndian(&buffer[14]);
+ voip_metric_.roundTripDelay =
+ ByteReader<uint16_t>::ReadBigEndian(&buffer[16]);
+ voip_metric_.endSystemDelay =
+ ByteReader<uint16_t>::ReadBigEndian(&buffer[18]);
+ voip_metric_.signalLevel = buffer[20];
+ voip_metric_.noiseLevel = buffer[21];
+ voip_metric_.RERL = buffer[22];
+ voip_metric_.Gmin = buffer[23];
+ voip_metric_.Rfactor = buffer[24];
+ voip_metric_.extRfactor = buffer[25];
+ voip_metric_.MOSLQ = buffer[26];
+ voip_metric_.MOSCQ = buffer[27];
+ voip_metric_.RXconfig = buffer[28];
+ // reserved = buffer[29];
+ voip_metric_.JBnominal = ByteReader<uint16_t>::ReadBigEndian(&buffer[30]);
+ voip_metric_.JBmax = ByteReader<uint16_t>::ReadBigEndian(&buffer[32]);
+ voip_metric_.JBabsMax = ByteReader<uint16_t>::ReadBigEndian(&buffer[34]);
+}
+
+void VoipMetric::Create(uint8_t* buffer) const {
+ const uint8_t kReserved = 0;
+ buffer[0] = kBlockType;
+ buffer[1] = kReserved;
+ ByteWriter<uint16_t>::WriteBigEndian(&buffer[2], kBlockLength);
+ ByteWriter<uint32_t>::WriteBigEndian(&buffer[4], ssrc_);
+ buffer[8] = voip_metric_.lossRate;
+ buffer[9] = voip_metric_.discardRate;
+ buffer[10] = voip_metric_.burstDensity;
+ buffer[11] = voip_metric_.gapDensity;
+ ByteWriter<uint16_t>::WriteBigEndian(&buffer[12], voip_metric_.burstDuration);
+ ByteWriter<uint16_t>::WriteBigEndian(&buffer[14], voip_metric_.gapDuration);
+ ByteWriter<uint16_t>::WriteBigEndian(&buffer[16],
+ voip_metric_.roundTripDelay);
+ ByteWriter<uint16_t>::WriteBigEndian(&buffer[18],
+ voip_metric_.endSystemDelay);
+ buffer[20] = voip_metric_.signalLevel;
+ buffer[21] = voip_metric_.noiseLevel;
+ buffer[22] = voip_metric_.RERL;
+ buffer[23] = voip_metric_.Gmin;
+ buffer[24] = voip_metric_.Rfactor;
+ buffer[25] = voip_metric_.extRfactor;
+ buffer[26] = voip_metric_.MOSLQ;
+ buffer[27] = voip_metric_.MOSCQ;
+ buffer[28] = voip_metric_.RXconfig;
+ buffer[29] = kReserved;
+ ByteWriter<uint16_t>::WriteBigEndian(&buffer[30], voip_metric_.JBnominal);
+ ByteWriter<uint16_t>::WriteBigEndian(&buffer[32], voip_metric_.JBmax);
+ ByteWriter<uint16_t>::WriteBigEndian(&buffer[34], voip_metric_.JBabsMax);
+}
+
+} // namespace rtcp
+} // namespace webrtc
diff --git a/webrtc/modules/rtp_rtcp/source/rtcp_packet/voip_metric.h b/webrtc/modules/rtp_rtcp/source/rtcp_packet/voip_metric.h
new file mode 100644
index 0000000000..9e3e41995a
--- /dev/null
+++ b/webrtc/modules/rtp_rtcp/source/rtcp_packet/voip_metric.h
@@ -0,0 +1,53 @@
+/*
+ * 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_VOIP_METRIC_H_
+#define WEBRTC_MODULES_RTP_RTCP_SOURCE_RTCP_PACKET_VOIP_METRIC_H_
+
+#include "webrtc/base/basictypes.h"
+#include "webrtc/modules/include/module_common_types.h"
+
+namespace webrtc {
+namespace rtcp {
+
+class VoipMetric {
+ public:
+ static const uint8_t kBlockType = 7;
+ static const uint16_t kBlockLength = 8;
+ static const size_t kLength = 4 * (kBlockLength + 1); // 36
+ VoipMetric();
+ VoipMetric(const VoipMetric&) = default;
+ ~VoipMetric() {}
+
+ VoipMetric& operator=(const VoipMetric&) = default;
+
+ void Parse(const uint8_t* buffer);
+
+ // Fills buffer with the VoipMetric.
+ // Consumes VoipMetric::kLength bytes.
+ void Create(uint8_t* buffer) const;
+
+ void To(uint32_t ssrc) { ssrc_ = ssrc; }
+ void WithVoipMetric(const RTCPVoIPMetric& voip_metric) {
+ voip_metric_ = voip_metric;
+ }
+
+ uint32_t ssrc() const { return ssrc_; }
+ const RTCPVoIPMetric& voip_metric() const { return voip_metric_; }
+
+ private:
+ uint32_t ssrc_;
+ RTCPVoIPMetric voip_metric_;
+};
+
+} // namespace rtcp
+} // namespace webrtc
+#endif // WEBRTC_MODULES_RTP_RTCP_SOURCE_RTCP_PACKET_VOIP_METRIC_H_
diff --git a/webrtc/modules/rtp_rtcp/source/rtcp_packet/voip_metric_unittest.cc b/webrtc/modules/rtp_rtcp/source/rtcp_packet/voip_metric_unittest.cc
new file mode 100644
index 0000000000..44c82d67a9
--- /dev/null
+++ b/webrtc/modules/rtp_rtcp/source/rtcp_packet/voip_metric_unittest.cc
@@ -0,0 +1,93 @@
+/*
+ * 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/voip_metric.h"
+
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace webrtc {
+namespace rtcp {
+namespace {
+
+const uint32_t kRemoteSsrc = 0x23456789;
+const uint8_t kBlock[] = {0x07, 0x00, 0x00, 0x08, 0x23, 0x45, 0x67, 0x89,
+ 0x01, 0x02, 0x03, 0x04, 0x11, 0x12, 0x22, 0x23,
+ 0x33, 0x34, 0x44, 0x45, 0x05, 0x06, 0x07, 0x08,
+ 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x00, 0x55, 0x56,
+ 0x66, 0x67, 0x77, 0x78};
+const size_t kBlockSizeBytes = sizeof(kBlock);
+static_assert(
+ kBlockSizeBytes == VoipMetric::kLength,
+ "Size of manually created Voip Metric block should match class constant");
+
+TEST(RtcpPacketVoipMetricTest, Create) {
+ uint8_t buffer[VoipMetric::kLength];
+ RTCPVoIPMetric metric;
+ metric.lossRate = 1;
+ metric.discardRate = 2;
+ metric.burstDensity = 3;
+ metric.gapDensity = 4;
+ metric.burstDuration = 0x1112;
+ metric.gapDuration = 0x2223;
+ metric.roundTripDelay = 0x3334;
+ metric.endSystemDelay = 0x4445;
+ 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 = 0x5556;
+ metric.JBmax = 0x6667;
+ metric.JBabsMax = 0x7778;
+ VoipMetric metric_block;
+ metric_block.To(kRemoteSsrc);
+ metric_block.WithVoipMetric(metric);
+
+ metric_block.Create(buffer);
+ EXPECT_EQ(0, memcmp(buffer, kBlock, kBlockSizeBytes));
+}
+
+TEST(RtcpPacketVoipMetricTest, Parse) {
+ VoipMetric read_metric;
+ read_metric.Parse(kBlock);
+
+ // Run checks on const object to ensure all accessors have const modifier.
+ const VoipMetric& parsed = read_metric;
+
+ EXPECT_EQ(kRemoteSsrc, parsed.ssrc());
+ EXPECT_EQ(1, parsed.voip_metric().lossRate);
+ EXPECT_EQ(2, parsed.voip_metric().discardRate);
+ EXPECT_EQ(3, parsed.voip_metric().burstDensity);
+ EXPECT_EQ(4, parsed.voip_metric().gapDensity);
+ EXPECT_EQ(0x1112, parsed.voip_metric().burstDuration);
+ EXPECT_EQ(0x2223, parsed.voip_metric().gapDuration);
+ EXPECT_EQ(0x3334, parsed.voip_metric().roundTripDelay);
+ EXPECT_EQ(0x4445, parsed.voip_metric().endSystemDelay);
+ EXPECT_EQ(5, parsed.voip_metric().signalLevel);
+ EXPECT_EQ(6, parsed.voip_metric().noiseLevel);
+ EXPECT_EQ(7, parsed.voip_metric().RERL);
+ EXPECT_EQ(8, parsed.voip_metric().Gmin);
+ EXPECT_EQ(9, parsed.voip_metric().Rfactor);
+ EXPECT_EQ(10, parsed.voip_metric().extRfactor);
+ EXPECT_EQ(11, parsed.voip_metric().MOSLQ);
+ EXPECT_EQ(12, parsed.voip_metric().MOSCQ);
+ EXPECT_EQ(13, parsed.voip_metric().RXconfig);
+ EXPECT_EQ(0x5556, parsed.voip_metric().JBnominal);
+ EXPECT_EQ(0x6667, parsed.voip_metric().JBmax);
+ EXPECT_EQ(0x7778, parsed.voip_metric().JBabsMax);
+}
+
+} // namespace
+} // namespace rtcp
+} // namespace webrtc