RtpPacket class introduced.
BUG=webrtc:1994, webrtc:5261
Review URL: https://codereview.webrtc.org/1841453004
Cr-Commit-Position: refs/heads/master@{#12444}
diff --git a/webrtc/modules/modules.gyp b/webrtc/modules/modules.gyp
index 8ae5bbb..6474253 100644
--- a/webrtc/modules/modules.gyp
+++ b/webrtc/modules/modules.gyp
@@ -337,6 +337,7 @@
'rtp_rtcp/source/rtp_format_vp8_unittest.cc',
'rtp_rtcp/source/rtp_format_vp9_unittest.cc',
'rtp_rtcp/source/rtp_packet_history_unittest.cc',
+ 'rtp_rtcp/source/rtp_packet_unittest.cc',
'rtp_rtcp/source/rtp_payload_registry_unittest.cc',
'rtp_rtcp/source/rtp_rtcp_impl_unittest.cc',
'rtp_rtcp/source/rtp_header_extension_unittest.cc',
diff --git a/webrtc/modules/rtp_rtcp/BUILD.gn b/webrtc/modules/rtp_rtcp/BUILD.gn
index d386951..9d69811 100644
--- a/webrtc/modules/rtp_rtcp/BUILD.gn
+++ b/webrtc/modules/rtp_rtcp/BUILD.gn
@@ -118,9 +118,15 @@
"source/rtp_format_vp9.h",
"source/rtp_header_extension.cc",
"source/rtp_header_extension.h",
+ "source/rtp_header_extensions.cc",
+ "source/rtp_header_extensions.h",
"source/rtp_header_parser.cc",
+ "source/rtp_packet.cc",
+ "source/rtp_packet.h",
"source/rtp_packet_history.cc",
"source/rtp_packet_history.h",
+ "source/rtp_packet_received.h",
+ "source/rtp_packet_to_send.h",
"source/rtp_payload_registry.cc",
"source/rtp_receiver_audio.cc",
"source/rtp_receiver_audio.h",
diff --git a/webrtc/modules/rtp_rtcp/rtp_rtcp.gypi b/webrtc/modules/rtp_rtcp/rtp_rtcp.gypi
index 23a64b7..3f1e935 100644
--- a/webrtc/modules/rtp_rtcp/rtp_rtcp.gypi
+++ b/webrtc/modules/rtp_rtcp/rtp_rtcp.gypi
@@ -35,10 +35,6 @@
'source/receive_statistics_impl.cc',
'source/receive_statistics_impl.h',
'source/remote_ntp_time_estimator.cc',
- 'source/rtp_header_parser.cc',
- 'source/rtp_rtcp_config.h',
- 'source/rtp_rtcp_impl.cc',
- 'source/rtp_rtcp_impl.h',
'source/rtcp_packet.cc',
'source/rtcp_packet.h',
'source/rtcp_packet/app.cc',
@@ -103,8 +99,18 @@
'source/rtcp_utility.h',
'source/rtp_header_extension.cc',
'source/rtp_header_extension.h',
+ 'source/rtp_header_extensions.cc',
+ 'source/rtp_header_extensions.h',
+ 'source/rtp_header_parser.cc',
+ 'source/rtp_packet.cc',
+ 'source/rtp_packet.h',
+ 'source/rtp_packet_received.h',
+ 'source/rtp_packet_to_send.h',
'source/rtp_receiver_impl.cc',
'source/rtp_receiver_impl.h',
+ 'source/rtp_rtcp_config.h',
+ 'source/rtp_rtcp_impl.cc',
+ 'source/rtp_rtcp_impl.h',
'source/rtp_sender.cc',
'source/rtp_sender.h',
'source/rtp_utility.cc',
diff --git a/webrtc/modules/rtp_rtcp/source/rtp_header_extension.cc b/webrtc/modules/rtp_rtcp/source/rtp_header_extension.cc
index 8605925..2c2a0a1 100644
--- a/webrtc/modules/rtp_rtcp/source/rtp_header_extension.cc
+++ b/webrtc/modules/rtp_rtcp/source/rtp_header_extension.cc
@@ -112,6 +112,14 @@
return 0;
}
+RTPExtensionType RtpHeaderExtensionMap::GetType(uint8_t id) const {
+ auto it = extensionMap_.find(id);
+ if (it == extensionMap_.end()) {
+ return kInvalidType;
+ }
+ return it->second->type;
+}
+
int32_t RtpHeaderExtensionMap::GetId(const RTPExtensionType type,
uint8_t* id) const {
assert(id);
@@ -129,6 +137,14 @@
return -1;
}
+uint8_t RtpHeaderExtensionMap::GetId(RTPExtensionType type) const {
+ for (auto kv : extensionMap_) {
+ if (kv.second->type == type)
+ return kv.first;
+ }
+ return kInvalidId;
+}
+
size_t RtpHeaderExtensionMap::GetTotalLengthInBytes() const {
// Get length for each extension block.
size_t length = 0;
diff --git a/webrtc/modules/rtp_rtcp/source/rtp_header_extension.h b/webrtc/modules/rtp_rtcp/source/rtp_header_extension.h
index 342e38a..beaf989 100644
--- a/webrtc/modules/rtp_rtcp/source/rtp_header_extension.h
+++ b/webrtc/modules/rtp_rtcp/source/rtp_header_extension.h
@@ -70,6 +70,8 @@
class RtpHeaderExtensionMap {
public:
+ static constexpr RTPExtensionType kInvalidType = kRtpExtensionNone;
+ static constexpr uint8_t kInvalidId = 0;
RtpHeaderExtensionMap();
~RtpHeaderExtensionMap();
@@ -89,8 +91,12 @@
bool IsRegistered(RTPExtensionType type) const;
int32_t GetType(const uint8_t id, RTPExtensionType* type) const;
+ // Return kInvalidType if not found.
+ RTPExtensionType GetType(uint8_t id) const;
int32_t GetId(const RTPExtensionType type, uint8_t* id) const;
+ // Return kInvalidId if not found.
+ uint8_t GetId(RTPExtensionType type) const;
//
// Methods below ignore any inactive rtp header extensions.
diff --git a/webrtc/modules/rtp_rtcp/source/rtp_header_extensions.cc b/webrtc/modules/rtp_rtcp/source/rtp_header_extensions.cc
new file mode 100644
index 0000000..a551b15
--- /dev/null
+++ b/webrtc/modules/rtp_rtcp/source/rtp_header_extensions.cc
@@ -0,0 +1,203 @@
+/*
+ * 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/rtp_header_extensions.h"
+
+#include "webrtc/base/checks.h"
+#include "webrtc/base/logging.h"
+#include "webrtc/modules/rtp_rtcp/include/rtp_cvo.h"
+#include "webrtc/modules/rtp_rtcp/source/byte_io.h"
+
+namespace webrtc {
+// Absolute send time in RTP streams.
+//
+// The absolute send time is signaled to the receiver in-band using the
+// general mechanism for RTP header extensions [RFC5285]. The payload
+// of this extension (the transmitted value) is a 24-bit unsigned integer
+// containing the sender's current time in seconds as a fixed point number
+// with 18 bits fractional part.
+//
+// The form of the absolute send time extension block:
+//
+// 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
+// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+// | ID | len=2 | absolute send time |
+// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+const char* AbsoluteSendTime::kName =
+ "http://www.webrtc.org/experiments/rtp-hdrext/abs-send-time";
+bool AbsoluteSendTime::IsSupportedFor(MediaType type) {
+ return true;
+}
+
+bool AbsoluteSendTime::Parse(const uint8_t* data, uint32_t* value) {
+ *value = ByteReader<uint32_t, 3>::ReadBigEndian(data);
+ return true;
+}
+
+bool AbsoluteSendTime::Write(uint8_t* data, int64_t time_ms) {
+ const uint32_t kAbsSendTimeFraction = 18;
+ uint32_t time_24_bits =
+ static_cast<uint32_t>(((time_ms << kAbsSendTimeFraction) + 500) / 1000) &
+ 0x00FFFFFF;
+
+ ByteWriter<uint32_t, 3>::WriteBigEndian(data, time_24_bits);
+ return true;
+}
+
+// An RTP Header Extension for Client-to-Mixer Audio Level Indication
+//
+// https://datatracker.ietf.org/doc/draft-lennox-avt-rtp-audio-level-exthdr/
+//
+// The form of the audio level extension block:
+//
+// 0 1
+// 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5
+// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+// | ID | len=0 |V| level |
+// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+//
+const char* AudioLevel::kName = "urn:ietf:params:rtp-hdrext:ssrc-audio-level";
+bool AudioLevel::IsSupportedFor(MediaType type) {
+ switch (type) {
+ case MediaType::ANY:
+ case MediaType::AUDIO:
+ return true;
+ case MediaType::VIDEO:
+ case MediaType::DATA:
+ return false;
+ }
+ RTC_NOTREACHED();
+ return false;
+}
+
+bool AudioLevel::Parse(const uint8_t* data,
+ bool* voice_activity,
+ uint8_t* audio_level) {
+ *voice_activity = (data[0] & 0x80) != 0;
+ *audio_level = data[0] & 0x7F;
+ return true;
+}
+
+bool AudioLevel::Write(uint8_t* data,
+ bool voice_activity,
+ uint8_t audio_level) {
+ RTC_CHECK_LE(audio_level, 0x7f);
+ data[0] = (voice_activity ? 0x80 : 0x00) | audio_level;
+ return true;
+}
+
+// From RFC 5450: Transmission Time Offsets in RTP Streams.
+//
+// The transmission time is signaled to the receiver in-band using the
+// general mechanism for RTP header extensions [RFC5285]. The payload
+// of this extension (the transmitted value) is a 24-bit signed integer.
+// When added to the RTP timestamp of the packet, it represents the
+// "effective" RTP transmission time of the packet, on the RTP
+// timescale.
+//
+// The form of the transmission offset extension block:
+//
+// 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
+// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+// | ID | len=2 | transmission offset |
+// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+const char* TransmissionOffset::kName = "urn:ietf:params:rtp-hdrext:toffset";
+bool TransmissionOffset::IsSupportedFor(MediaType type) {
+ switch (type) {
+ case MediaType::ANY:
+ case MediaType::VIDEO:
+ return true;
+ case MediaType::AUDIO:
+ case MediaType::DATA:
+ return false;
+ }
+ RTC_NOTREACHED();
+ return false;
+}
+
+bool TransmissionOffset::Parse(const uint8_t* data, int32_t* value) {
+ *value = ByteReader<int32_t, 3>::ReadBigEndian(data);
+ return true;
+}
+
+bool TransmissionOffset::Write(uint8_t* data, int64_t value) {
+ RTC_CHECK_LE(value, 0x00ffffff);
+ ByteWriter<int32_t, 3>::WriteBigEndian(data, value);
+ return true;
+}
+
+// 0 1 2
+// 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3
+// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+// | ID | L=1 |transport wide sequence number |
+// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+const char* TransportSequenceNumber::kName =
+ "http://www.ietf.org/id/draft-holmer-rmcat-transport-wide-cc-extensions";
+bool TransportSequenceNumber::IsSupportedFor(MediaType type) {
+ return true;
+}
+
+bool TransportSequenceNumber::Parse(const uint8_t* data, uint16_t* value) {
+ *value = ByteReader<uint16_t>::ReadBigEndian(data);
+ return true;
+}
+
+bool TransportSequenceNumber::Write(uint8_t* data, uint16_t value) {
+ ByteWriter<uint16_t>::WriteBigEndian(data, value);
+ return true;
+}
+
+// Coordination of Video Orientation in RTP streams.
+//
+// Coordination of Video Orientation consists in signaling of the current
+// orientation of the image captured on the sender side to the receiver for
+// appropriate rendering and displaying.
+//
+// 0 1
+// 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5
+// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+// | ID | len=0 |0 0 0 0 C F R R|
+// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+const char* VideoOrientation::kName = "urn:3gpp:video-orientation";
+bool VideoOrientation::IsSupportedFor(MediaType type) {
+ switch (type) {
+ case MediaType::ANY:
+ case MediaType::VIDEO:
+ return true;
+ case MediaType::AUDIO:
+ case MediaType::DATA:
+ return false;
+ }
+ RTC_NOTREACHED();
+ return false;
+}
+
+bool VideoOrientation::Parse(const uint8_t* data, VideoRotation* rotation) {
+ *rotation = ConvertCVOByteToVideoRotation(data[0] & 0x03);
+ return true;
+}
+
+bool VideoOrientation::Write(uint8_t* data, VideoRotation rotation) {
+ data[0] = ConvertVideoRotationToCVOByte(rotation);
+ return true;
+}
+
+bool VideoOrientation::Parse(const uint8_t* data, uint8_t* value) {
+ *value = data[0];
+ return true;
+}
+
+bool VideoOrientation::Write(uint8_t* data, uint8_t value) {
+ data[0] = value;
+ return true;
+}
+} // namespace webrtc
diff --git a/webrtc/modules/rtp_rtcp/source/rtp_header_extensions.h b/webrtc/modules/rtp_rtcp/source/rtp_header_extensions.h
new file mode 100644
index 0000000..cdbf806
--- /dev/null
+++ b/webrtc/modules/rtp_rtcp/source/rtp_header_extensions.h
@@ -0,0 +1,75 @@
+/*
+ * 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_RTP_HEADER_EXTENSIONS_H_
+#define WEBRTC_MODULES_RTP_RTCP_SOURCE_RTP_HEADER_EXTENSIONS_H_
+
+#include "webrtc/base/basictypes.h"
+#include "webrtc/call.h"
+#include "webrtc/common_video/rotation.h"
+#include "webrtc/modules/rtp_rtcp/include/rtp_rtcp_defines.h"
+
+namespace webrtc {
+
+class AbsoluteSendTime {
+ public:
+ static constexpr RTPExtensionType kId = kRtpExtensionAbsoluteSendTime;
+ static constexpr uint8_t kValueSizeBytes = 3;
+ static const char* kName;
+ static bool IsSupportedFor(MediaType type);
+ static bool Parse(const uint8_t* data, uint32_t* time_ms);
+ static bool Write(uint8_t* data, int64_t time_ms);
+};
+
+class AudioLevel {
+ public:
+ static constexpr RTPExtensionType kId = kRtpExtensionAudioLevel;
+ static constexpr uint8_t kValueSizeBytes = 1;
+ static const char* kName;
+ static bool IsSupportedFor(MediaType type);
+ static bool Parse(const uint8_t* data,
+ bool* voice_activity,
+ uint8_t* audio_level);
+ static bool Write(uint8_t* data, bool voice_activity, uint8_t audio_level);
+};
+
+class TransmissionOffset {
+ public:
+ static constexpr RTPExtensionType kId = kRtpExtensionTransmissionTimeOffset;
+ static constexpr uint8_t kValueSizeBytes = 3;
+ static const char* kName;
+ static bool IsSupportedFor(MediaType type);
+ static bool Parse(const uint8_t* data, int32_t* time_ms);
+ static bool Write(uint8_t* data, int64_t time_ms);
+};
+
+class TransportSequenceNumber {
+ public:
+ static constexpr RTPExtensionType kId = kRtpExtensionTransportSequenceNumber;
+ static constexpr uint8_t kValueSizeBytes = 2;
+ static const char* kName;
+ static bool IsSupportedFor(MediaType type);
+ static bool Parse(const uint8_t* data, uint16_t* value);
+ static bool Write(uint8_t* data, uint16_t value);
+};
+
+class VideoOrientation {
+ public:
+ static constexpr RTPExtensionType kId = kRtpExtensionVideoRotation;
+ static constexpr uint8_t kValueSizeBytes = 1;
+ static const char* kName;
+ static bool IsSupportedFor(MediaType type);
+ static bool Parse(const uint8_t* data, VideoRotation* value);
+ static bool Write(uint8_t* data, VideoRotation value);
+ static bool Parse(const uint8_t* data, uint8_t* value);
+ static bool Write(uint8_t* data, uint8_t value);
+};
+
+} // namespace webrtc
+#endif // WEBRTC_MODULES_RTP_RTCP_SOURCE_RTP_HEADER_EXTENSIONS_H_
diff --git a/webrtc/modules/rtp_rtcp/source/rtp_packet.cc b/webrtc/modules/rtp_rtcp/source/rtp_packet.cc
new file mode 100644
index 0000000..f663486
--- /dev/null
+++ b/webrtc/modules/rtp_rtcp/source/rtp_packet.cc
@@ -0,0 +1,509 @@
+/*
+ * 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/rtp_packet.h"
+
+#include <cstring>
+
+#include "webrtc/base/checks.h"
+#include "webrtc/base/logging.h"
+#include "webrtc/base/random.h"
+#include "webrtc/common_types.h"
+#include "webrtc/modules/rtp_rtcp/source/rtp_header_extension.h"
+#include "webrtc/modules/rtp_rtcp/source/rtp_header_extensions.h"
+#include "webrtc/modules/rtp_rtcp/source/byte_io.h"
+
+namespace webrtc {
+namespace rtp {
+namespace {
+constexpr size_t kFixedHeaderSize = 12;
+constexpr uint8_t kRtpVersion = 2;
+constexpr uint16_t kOneByteExtensionId = 0xBEDE;
+constexpr size_t kOneByteHeaderSize = 1;
+constexpr size_t kDefaultPacketSize = 1500;
+} // namespace
+// 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|X| CC |M| PT | sequence number |
+// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+// | timestamp |
+// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+// | synchronization source (SSRC) identifier |
+// +=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+
+// | Contributing source (CSRC) identifiers |
+// | .... |
+// +=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+
+// |One-byte eXtensions id = 0xbede| length in 32bits |
+// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+// | Extensions |
+// | .... |
+// +=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+
+// | Payload |
+// | .... : padding... |
+// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+// | padding | Padding size |
+// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+Packet::Packet(const ExtensionManager* extensions)
+ : extensions_(extensions), buffer_(kDefaultPacketSize) {
+ Clear();
+}
+
+Packet::Packet(const ExtensionManager* extensions, size_t capacity)
+ : extensions_(extensions), buffer_(capacity) {
+ RTC_DCHECK_GE(capacity, kFixedHeaderSize);
+ Clear();
+}
+
+Packet::~Packet() {}
+
+void Packet::IdentifyExtensions(const ExtensionManager* extensions) {
+ RTC_DCHECK(extensions);
+ extensions_ = extensions;
+ for (size_t i = 0; i < num_extensions_; ++i) {
+ uint8_t id = data()[extension_entries_[i].offset - 1] >> 4;
+ extension_entries_[i].type = extensions_->GetType(id);
+ }
+}
+
+bool Packet::Parse(const uint8_t* buffer, size_t buffer_size) {
+ if (!ParseBuffer(buffer, buffer_size)) {
+ Clear();
+ return false;
+ }
+ RTC_DCHECK_EQ(size(), buffer_size);
+ buffer_.SetData(buffer, buffer_size);
+ return true;
+}
+
+bool Packet::Parse(rtc::Buffer buffer) {
+ if (!ParseBuffer(buffer.data(), buffer.size())) {
+ Clear();
+ return false;
+ }
+ RTC_DCHECK_EQ(size(), buffer.size());
+ buffer_ = std::move(buffer);
+ return true;
+}
+
+bool Packet::Marker() const {
+ RTC_DCHECK_EQ(marker_, (data()[1] & 0x80) != 0);
+ return marker_;
+}
+
+uint8_t Packet::PayloadType() const {
+ RTC_DCHECK_EQ(payload_type_, data()[1] & 0x7f);
+ return payload_type_;
+}
+
+uint16_t Packet::SequenceNumber() const {
+ RTC_DCHECK_EQ(sequence_number_,
+ ByteReader<uint16_t>::ReadBigEndian(data() + 2));
+ return sequence_number_;
+}
+
+uint32_t Packet::Timestamp() const {
+ RTC_DCHECK_EQ(timestamp_, ByteReader<uint32_t>::ReadBigEndian(data() + 4));
+ return timestamp_;
+}
+
+uint32_t Packet::Ssrc() const {
+ RTC_DCHECK_EQ(ssrc_, ByteReader<uint32_t>::ReadBigEndian(data() + 8));
+ return ssrc_;
+}
+
+std::vector<uint32_t> Packet::Csrcs() const {
+ size_t num_csrc = data()[0] & 0x0F;
+ RTC_DCHECK_GE(capacity(), kFixedHeaderSize + num_csrc * 4);
+ std::vector<uint32_t> csrcs(num_csrc);
+ for (size_t i = 0; i < num_csrc; ++i) {
+ csrcs[i] =
+ ByteReader<uint32_t>::ReadBigEndian(&data()[kFixedHeaderSize + i * 4]);
+ }
+ return csrcs;
+}
+
+void Packet::GetHeader(RTPHeader* header) const {
+ header->markerBit = Marker();
+ header->payloadType = PayloadType();
+ header->sequenceNumber = SequenceNumber();
+ header->timestamp = Timestamp();
+ header->ssrc = Ssrc();
+ std::vector<uint32_t> csrcs = Csrcs();
+ header->numCSRCs = csrcs.size();
+ for (size_t i = 0; i < csrcs.size(); ++i) {
+ header->arrOfCSRCs[i] = csrcs[i];
+ }
+ header->paddingLength = padding_size();
+ header->headerLength = headers_size();
+ header->payload_type_frequency = 0;
+ header->extension.hasTransmissionTimeOffset =
+ GetExtension<TransmissionOffset>(
+ &header->extension.transmissionTimeOffset);
+ header->extension.hasAbsoluteSendTime =
+ GetExtension<AbsoluteSendTime>(&header->extension.absoluteSendTime);
+ header->extension.hasTransportSequenceNumber =
+ GetExtension<TransportSequenceNumber>(
+ &header->extension.transportSequenceNumber);
+ header->extension.hasAudioLevel = GetExtension<AudioLevel>(
+ &header->extension.voiceActivity, &header->extension.audioLevel);
+ header->extension.hasVideoRotation =
+ GetExtension<VideoOrientation>(&header->extension.videoRotation);
+}
+
+size_t Packet::headers_size() const {
+ return payload_offset_;
+}
+
+size_t Packet::payload_size() const {
+ return payload_size_;
+}
+
+size_t Packet::padding_size() const {
+ return padding_size_;
+}
+
+const uint8_t* Packet::payload() const {
+ return data() + payload_offset_;
+}
+
+size_t Packet::capacity() const {
+ return buffer_.size();
+}
+
+size_t Packet::size() const {
+ return payload_offset_ + payload_size_ + padding_size_;
+}
+
+const uint8_t* Packet::data() const {
+ return buffer_.data();
+}
+
+size_t Packet::FreeCapacity() const {
+ return capacity() - size();
+}
+
+size_t Packet::MaxPayloadSize() const {
+ return capacity() - payload_offset_;
+}
+
+void Packet::CopyHeader(const Packet& packet) {
+ RTC_DCHECK_GE(capacity(), packet.headers_size());
+
+ marker_ = packet.marker_;
+ payload_type_ = packet.payload_type_;
+ sequence_number_ = packet.sequence_number_;
+ timestamp_ = packet.timestamp_;
+ ssrc_ = packet.ssrc_;
+ payload_offset_ = packet.payload_offset_;
+ num_extensions_ = packet.num_extensions_;
+ for (size_t i = 0; i < num_extensions_; ++i) {
+ extension_entries_[i] = packet.extension_entries_[i];
+ }
+ extensions_size_ = packet.extensions_size_;
+ buffer_.SetData(packet.data(), packet.headers_size());
+ // Reset payload and padding.
+ payload_size_ = 0;
+ padding_size_ = 0;
+}
+
+void Packet::SetMarker(bool marker_bit) {
+ marker_ = marker_bit;
+ if (marker_) {
+ WriteAt(1, data()[1] | 0x80);
+ } else {
+ WriteAt(1, data()[1] & 0x7F);
+ }
+}
+
+void Packet::SetPayloadType(uint8_t payload_type) {
+ RTC_DCHECK_LE(payload_type, 0x7Fu);
+ payload_type_ = payload_type;
+ WriteAt(1, (data()[1] & 0x80) | payload_type);
+}
+
+void Packet::SetSequenceNumber(uint16_t seq_no) {
+ sequence_number_ = seq_no;
+ ByteWriter<uint16_t>::WriteBigEndian(WriteAt(2), seq_no);
+}
+
+void Packet::SetTimestamp(uint32_t timestamp) {
+ timestamp_ = timestamp;
+ ByteWriter<uint32_t>::WriteBigEndian(WriteAt(4), timestamp);
+}
+
+void Packet::SetSsrc(uint32_t ssrc) {
+ ssrc_ = ssrc;
+ ByteWriter<uint32_t>::WriteBigEndian(WriteAt(8), ssrc);
+}
+
+void Packet::SetCsrcs(const std::vector<uint32_t>& csrcs) {
+ RTC_DCHECK_EQ(num_extensions_, 0u);
+ RTC_DCHECK_EQ(payload_size_, 0u);
+ RTC_DCHECK_EQ(padding_size_, 0u);
+ RTC_DCHECK_LE(csrcs.size(), 0x0fu);
+ RTC_DCHECK_LE(kFixedHeaderSize + 4 * csrcs.size(), capacity());
+ payload_offset_ = kFixedHeaderSize + 4 * csrcs.size();
+ WriteAt(0, (data()[0] & 0xF0) | csrcs.size());
+ size_t offset = kFixedHeaderSize;
+ for (uint32_t csrc : csrcs) {
+ ByteWriter<uint32_t>::WriteBigEndian(WriteAt(offset), csrc);
+ offset += 4;
+ }
+}
+
+uint8_t* Packet::AllocatePayload(size_t size_bytes) {
+ RTC_DCHECK_EQ(padding_size_, 0u);
+ if (payload_offset_ + size_bytes > capacity()) {
+ LOG(LS_WARNING) << "Cannot set payload, not enough space in buffer.";
+ return nullptr;
+ }
+ payload_size_ = size_bytes;
+ return WriteAt(payload_offset_);
+}
+
+void Packet::SetPayloadSize(size_t size_bytes) {
+ RTC_DCHECK_EQ(padding_size_, 0u);
+ RTC_DCHECK_LE(size_bytes, payload_size_);
+ payload_size_ = size_bytes;
+}
+
+bool Packet::SetPadding(uint8_t size_bytes, Random* random) {
+ RTC_DCHECK(random);
+ if (payload_offset_ + payload_size_ + size_bytes > capacity()) {
+ LOG(LS_WARNING) << "Cannot set padding size " << size_bytes << ", only "
+ << (capacity() - payload_offset_ - payload_size_)
+ << " bytes left in buffer.";
+ return false;
+ }
+ padding_size_ = size_bytes;
+ if (padding_size_ > 0) {
+ size_t padding_offset = payload_offset_ + payload_size_;
+ size_t padding_end = padding_offset + padding_size_;
+ for (size_t offset = padding_offset; offset < padding_end - 1; ++offset) {
+ WriteAt(offset, random->Rand<uint8_t>());
+ }
+ WriteAt(padding_end - 1, padding_size_);
+ WriteAt(0, data()[0] | 0x20); // Set padding bit.
+ } else {
+ WriteAt(0, data()[0] & ~0x20); // Clear padding bit.
+ }
+ return true;
+}
+
+void Packet::Clear() {
+ marker_ = false;
+ payload_type_ = 0;
+ sequence_number_ = 0;
+ timestamp_ = 0;
+ ssrc_ = 0;
+ payload_offset_ = kFixedHeaderSize;
+ payload_size_ = 0;
+ padding_size_ = 0;
+ num_extensions_ = 0;
+ extensions_size_ = 0;
+
+ memset(WriteAt(0), 0, kFixedHeaderSize);
+ WriteAt(0, kRtpVersion << 6);
+}
+
+bool Packet::ParseBuffer(const uint8_t* buffer, size_t size) {
+ if (size < kFixedHeaderSize) {
+ return false;
+ }
+ const uint8_t version = buffer[0] >> 6;
+ if (version != kRtpVersion) {
+ return false;
+ }
+ const bool has_padding = (buffer[0] & 0x20) != 0;
+ const bool has_extension = (buffer[0] & 0x10) != 0;
+ const uint8_t number_of_crcs = buffer[0] & 0x0f;
+ marker_ = (buffer[1] & 0x80) != 0;
+ payload_type_ = buffer[1] & 0x7f;
+
+ sequence_number_ = ByteReader<uint16_t>::ReadBigEndian(&buffer[2]);
+ timestamp_ = ByteReader<uint32_t>::ReadBigEndian(&buffer[4]);
+ ssrc_ = ByteReader<uint32_t>::ReadBigEndian(&buffer[8]);
+ if (size < kFixedHeaderSize + number_of_crcs * 4) {
+ return false;
+ }
+ payload_offset_ = kFixedHeaderSize + number_of_crcs * 4;
+
+ if (has_padding) {
+ padding_size_ = buffer[size - 1];
+ if (padding_size_ == 0) {
+ LOG(LS_WARNING) << "Padding was set, but padding size is zero";
+ return false;
+ }
+ } else {
+ padding_size_ = 0;
+ }
+
+ num_extensions_ = 0;
+ extensions_size_ = 0;
+ if (has_extension) {
+ /* RTP header extension, 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
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ | defined by profile | length |
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ | header extension |
+ | .... |
+ */
+ size_t extension_offset = payload_offset_ + 4;
+ if (extension_offset > size) {
+ return false;
+ }
+ uint16_t profile =
+ ByteReader<uint16_t>::ReadBigEndian(&buffer[payload_offset_]);
+ size_t extensions_capacity =
+ ByteReader<uint16_t>::ReadBigEndian(&buffer[payload_offset_ + 2]);
+ extensions_capacity *= 4;
+ if (extension_offset + extensions_capacity > size) {
+ return false;
+ }
+ if (profile != kOneByteExtensionId) {
+ LOG(LS_WARNING) << "Unsupported rtp extension " << profile;
+ } else {
+ constexpr uint8_t kPaddingId = 0;
+ constexpr uint8_t kReservedId = 15;
+ while (extensions_size_ + kOneByteHeaderSize < extensions_capacity) {
+ uint8_t id = buffer[extension_offset + extensions_size_] >> 4;
+ if (id == kReservedId) {
+ break;
+ } else if (id == kPaddingId) {
+ extensions_size_++;
+ continue;
+ }
+ uint8_t length =
+ 1 + (buffer[extension_offset + extensions_size_] & 0xf);
+ extensions_size_ += kOneByteHeaderSize;
+ if (num_extensions_ >= kMaxExtensionHeaders) {
+ LOG(LS_WARNING) << "Too many extensions.";
+ return false;
+ }
+ extension_entries_[num_extensions_].type =
+ extensions_ ? extensions_->GetType(id)
+ : ExtensionManager::kInvalidType;
+ extension_entries_[num_extensions_].length = length;
+ extension_entries_[num_extensions_].offset =
+ extension_offset + extensions_size_;
+ num_extensions_++;
+ extensions_size_ += length;
+ }
+ }
+ payload_offset_ = extension_offset + extensions_capacity;
+ }
+
+ if (payload_offset_ + padding_size_ > size) {
+ return false;
+ }
+ payload_size_ = size - payload_offset_ - padding_size_;
+ return true;
+}
+
+bool Packet::FindExtension(ExtensionType type,
+ uint8_t length,
+ uint16_t* offset) const {
+ RTC_DCHECK(offset);
+ for (size_t i = 0; i < num_extensions_; ++i) {
+ if (extension_entries_[i].type == type) {
+ RTC_CHECK_EQ(length, extension_entries_[i].length)
+ << "Length mismatch for extension '" << type << "'"
+ << "should be " << length << ", received "
+ << extension_entries_[i].length;
+ *offset = extension_entries_[i].offset;
+ return true;
+ }
+ }
+ return false;
+}
+
+bool Packet::AllocateExtension(ExtensionType type,
+ uint8_t length,
+ uint16_t* offset) {
+ if (!extensions_) {
+ return false;
+ }
+ if (FindExtension(type, length, offset)) {
+ return true;
+ }
+
+ // Can't add new extension after payload/padding was set.
+ if (payload_size_ > 0) {
+ return false;
+ }
+ if (padding_size_ > 0) {
+ return false;
+ }
+
+ uint8_t extension_id = extensions_->GetId(type);
+ if (extension_id == ExtensionManager::kInvalidId) {
+ return false;
+ }
+ RTC_DCHECK_GT(length, 0u);
+ RTC_DCHECK_LE(length, 16u);
+
+ size_t num_csrc = data()[0] & 0x0F;
+ size_t extensions_offset = kFixedHeaderSize + (num_csrc * 4) + 4;
+ if (extensions_offset + extensions_size_ + kOneByteHeaderSize + length >
+ capacity()) {
+ LOG(LS_WARNING) << "Extension cannot be registered: "
+ "Not enough space left in buffer.";
+ return false;
+ }
+
+ uint16_t new_extensions_size =
+ extensions_size_ + kOneByteHeaderSize + length;
+ uint16_t extensions_words =
+ (new_extensions_size + 3) / 4; // Wrap up to 32bit.
+
+ // All checks passed, write down the extension.
+ if (num_extensions_ == 0) {
+ RTC_DCHECK_EQ(payload_offset_, kFixedHeaderSize + (num_csrc * 4));
+ RTC_DCHECK_EQ(extensions_size_, 0);
+ WriteAt(0, data()[0] | 0x10); // Set extension bit.
+ // Profile specific ID always set to OneByteExtensionHeader.
+ ByteWriter<uint16_t>::WriteBigEndian(WriteAt(extensions_offset - 4),
+ kOneByteExtensionId);
+ }
+
+ WriteAt(extensions_offset + extensions_size_,
+ (extension_id << 4) | (length - 1));
+ RTC_DCHECK(num_extensions_ < kMaxExtensionHeaders);
+ extension_entries_[num_extensions_].type = type;
+ extension_entries_[num_extensions_].length = length;
+ *offset = extensions_offset + kOneByteHeaderSize + extensions_size_;
+ extension_entries_[num_extensions_].offset = *offset;
+ ++num_extensions_;
+ extensions_size_ = new_extensions_size;
+
+ // Update header length field.
+ ByteWriter<uint16_t>::WriteBigEndian(WriteAt(extensions_offset - 2),
+ extensions_words);
+ // Fill extension padding place with zeroes.
+ size_t extension_padding_size = 4 * extensions_words - extensions_size_;
+ memset(WriteAt(extensions_offset + extensions_size_), 0,
+ extension_padding_size);
+ payload_offset_ = extensions_offset + 4 * extensions_words;
+ return true;
+}
+
+uint8_t* Packet::WriteAt(size_t offset) {
+ return buffer_.data() + offset;
+}
+
+void Packet::WriteAt(size_t offset, uint8_t byte) {
+ buffer_.data()[offset] = byte;
+}
+
+} // namespace rtp
+} // namespace webrtc
diff --git a/webrtc/modules/rtp_rtcp/source/rtp_packet.h b/webrtc/modules/rtp_rtcp/source/rtp_packet.h
new file mode 100644
index 0000000..9e9f4c1
--- /dev/null
+++ b/webrtc/modules/rtp_rtcp/source/rtp_packet.h
@@ -0,0 +1,186 @@
+/*
+ * 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_RTP_PACKET_H_
+#define WEBRTC_MODULES_RTP_RTCP_SOURCE_RTP_PACKET_H_
+
+#include <vector>
+
+#include "webrtc/base/basictypes.h"
+#include "webrtc/base/buffer.h"
+#include "webrtc/modules/rtp_rtcp/include/rtp_rtcp_defines.h"
+
+namespace webrtc {
+struct RTPHeader;
+class RtpHeaderExtensionMap;
+class Random;
+
+namespace rtp {
+class Packet {
+ public:
+ using ExtensionType = RTPExtensionType;
+ using ExtensionManager = RtpHeaderExtensionMap;
+ static constexpr size_t kMaxExtensionHeaders = 14;
+
+ // Parse and copy given buffer into Packet.
+ bool Parse(const uint8_t* buffer, size_t size);
+
+ // Parse and move given buffer into Packet.
+ bool Parse(rtc::Buffer packet);
+
+ // Maps parsed extensions to their types to allow use of GetExtension.
+ // Used after parsing when |extensions| can't be provided until base rtp
+ // header is parsed.
+ void IdentifyExtensions(const ExtensionManager* extensions);
+
+ // Header.
+ bool Marker() const;
+ uint8_t PayloadType() const;
+ uint16_t SequenceNumber() const;
+ uint32_t Timestamp() const;
+ uint32_t Ssrc() const;
+ std::vector<uint32_t> Csrcs() const;
+
+ // TODO(danilchap): Remove this function when all code update to use RtpPacket
+ // directly. Function is there just for easier backward compatibilty.
+ void GetHeader(RTPHeader* header) const;
+
+ size_t headers_size() const;
+
+ // Payload.
+ size_t payload_size() const;
+ size_t padding_size() const;
+ const uint8_t* payload() const;
+
+ // Buffer.
+ size_t capacity() const;
+ size_t size() const;
+ const uint8_t* data() const;
+ size_t FreeCapacity() const;
+ size_t MaxPayloadSize() const;
+
+ // Reset fields and buffer.
+ void Clear();
+
+ // Header setters.
+ void CopyHeader(const Packet& packet);
+ void SetMarker(bool marker_bit);
+ void SetPayloadType(uint8_t payload_type);
+ void SetSequenceNumber(uint16_t seq_no);
+ void SetTimestamp(uint32_t timestamp);
+ void SetSsrc(uint32_t ssrc);
+
+ // Writes csrc list. Assumes:
+ // a) There is enough room left in buffer.
+ // b) Extension headers, payload or padding data has not already been added.
+ void SetCsrcs(const std::vector<uint32_t>& csrcs);
+
+ // Header extensions.
+ template <typename Extension, typename... Values>
+ bool GetExtension(Values...) const;
+
+ template <typename Extension, typename... Values>
+ bool SetExtension(Values...);
+
+ template <typename Extension>
+ bool ReserveExtension();
+
+ // Reserve size_bytes for payload. Returns nullptr on failure.
+ uint8_t* AllocatePayload(size_t size_bytes);
+ void SetPayloadSize(size_t size_bytes);
+ bool SetPadding(uint8_t size_bytes, Random* random);
+
+ protected:
+ // |extensions| required for SetExtension/ReserveExtension functions during
+ // packet creating and used if available in Parse function.
+ // Adding and getting extensions will fail until |extensions| is
+ // provided via constructor or IdentifyExtensions function.
+ explicit Packet(const ExtensionManager* extensions);
+ Packet(const ExtensionManager* extensions, size_t capacity);
+ virtual ~Packet();
+
+ private:
+ struct ExtensionInfo {
+ ExtensionType type;
+ uint16_t offset;
+ uint8_t length;
+ };
+
+ // Helper function for Parse. Fill header fields using data in given buffer,
+ // but does not touch packet own buffer, leaving packet in invalid state.
+ bool ParseBuffer(const uint8_t* buffer, size_t size);
+
+ // Find an extension based on the type field of the parameter.
+ // If found, length field would be validated, the offset field will be set
+ // and true returned,
+ // otherwise the parameter will be unchanged and false is returned.
+ bool FindExtension(ExtensionType type,
+ uint8_t length,
+ uint16_t* offset) const;
+
+ // Find or allocate an extension, based on the type field of the parameter.
+ // If found, the length field be checked against what is already registered
+ // and the offset field will be set, then true is returned. If allocated, the
+ // length field will be used for allocation and the offset update to indicate
+ // position, the true is returned.
+ // If not found and allocations fails, false is returned and parameter remains
+ // unchanged.
+ bool AllocateExtension(ExtensionType type, uint8_t length, uint16_t* offset);
+
+ uint8_t* WriteAt(size_t offset);
+ void WriteAt(size_t offset, uint8_t byte);
+
+ const ExtensionManager* extensions_;
+
+ // Header.
+ bool marker_;
+ uint8_t payload_type_;
+ uint8_t padding_size_;
+ uint16_t sequence_number_;
+ uint32_t timestamp_;
+ uint32_t ssrc_;
+ size_t payload_offset_; // Match header size with csrcs and extensions.
+ size_t payload_size_;
+
+ uint8_t num_extensions_ = 0;
+ ExtensionInfo extension_entries_[kMaxExtensionHeaders];
+ uint16_t extensions_size_ = 0; // Unaligned.
+ rtc::Buffer buffer_;
+
+ RTC_DISALLOW_IMPLICIT_CONSTRUCTORS(Packet);
+};
+
+template <typename Extension, typename... Values>
+bool Packet::GetExtension(Values... values) const {
+ uint16_t offset = 0;
+ if (!FindExtension(Extension::kId, Extension::kValueSizeBytes, &offset))
+ return false;
+ return Extension::Parse(data() + offset, values...);
+}
+
+template <typename Extension, typename... Values>
+bool Packet::SetExtension(Values... values) {
+ uint16_t offset = 0;
+ if (!AllocateExtension(Extension::kId, Extension::kValueSizeBytes, &offset))
+ return false;
+ return Extension::Write(WriteAt(offset), values...);
+}
+
+template <typename Extension>
+bool Packet::ReserveExtension() {
+ uint16_t offset = 0;
+ if (!AllocateExtension(Extension::kId, Extension::kValueSizeBytes, &offset))
+ return false;
+ memset(WriteAt(offset), 0, Extension::kValueSizeBytes);
+ return true;
+}
+} // namespace rtp
+} // namespace webrtc
+
+#endif // WEBRTC_MODULES_RTP_RTCP_SOURCE_RTP_PACKET_H_
diff --git a/webrtc/modules/rtp_rtcp/source/rtp_packet_received.h b/webrtc/modules/rtp_rtcp/source/rtp_packet_received.h
new file mode 100644
index 0000000..e2222b9
--- /dev/null
+++ b/webrtc/modules/rtp_rtcp/source/rtp_packet_received.h
@@ -0,0 +1,56 @@
+/*
+ * Copyright (c) 2016 The WebRTC project authors. All Rights Reserved.
+ *
+ * Use of this source code is governed by a BSD-style license
+ * that can be found in the LICENSE file in the root of the source
+ * tree. An additional intellectual property rights grant can be found
+ * in the file PATENTS. All contributing project authors may
+ * be found in the AUTHORS file in the root of the source tree.
+ */
+#ifndef WEBRTC_MODULES_RTP_RTCP_SOURCE_RTP_PACKET_RECEIVED_H_
+#define WEBRTC_MODULES_RTP_RTCP_SOURCE_RTP_PACKET_RECEIVED_H_
+
+#include "webrtc/common_types.h"
+#include "webrtc/modules/rtp_rtcp/source/rtp_packet.h"
+#include "webrtc/system_wrappers/include/ntp_time.h"
+
+namespace webrtc {
+// Class to hold rtp packet with metadata for receiver side.
+class RtpPacketReceived : public rtp::Packet {
+ public:
+ RtpPacketReceived() : Packet(nullptr) {}
+ explicit RtpPacketReceived(const ExtensionManager* extensions)
+ : Packet(extensions) {}
+
+ void GetHeader(RTPHeader* header) const {
+ Packet::GetHeader(header);
+ header->payload_type_frequency = payload_type_frequency();
+ }
+
+ // Time in local time base as close as it can to packet arrived on the
+ // network.
+ int64_t arrival_time_ms() const { return arrival_time_ms_; }
+ void set_arrival_time_ms(int64_t time) { arrival_time_ms_ = time; }
+
+ // Estimated from Timestamp() using rtcp Sender Reports.
+ NtpTime capture_ntp_time() const { return capture_time_; }
+ void set_capture_ntp_time(NtpTime time) { capture_time_ = time; }
+
+ // Flag if packet arrived via rtx.
+ bool retransmit() const { return retransmit_; }
+ void set_retransmit(bool value) { retransmit_ = value; }
+
+ int payload_type_frequency() const { return payload_type_frequency_; }
+ void set_payload_type_frequency(int value) {
+ payload_type_frequency_ = value;
+ }
+
+ private:
+ NtpTime capture_time_;
+ int64_t arrival_time_ms_ = 0;
+ int payload_type_frequency_ = 0;
+ bool retransmit_ = false;
+};
+
+} // namespace webrtc
+#endif // WEBRTC_MODULES_RTP_RTCP_SOURCE_RTP_PACKET_RECEIVED_H_
diff --git a/webrtc/modules/rtp_rtcp/source/rtp_packet_to_send.h b/webrtc/modules/rtp_rtcp/source/rtp_packet_to_send.h
new file mode 100644
index 0000000..ad749ff
--- /dev/null
+++ b/webrtc/modules/rtp_rtcp/source/rtp_packet_to_send.h
@@ -0,0 +1,33 @@
+/*
+ * 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_RTP_PACKET_TO_SEND_H_
+#define WEBRTC_MODULES_RTP_RTCP_SOURCE_RTP_PACKET_TO_SEND_H_
+
+#include "webrtc/modules/rtp_rtcp/source/rtp_packet.h"
+
+namespace webrtc {
+// Class to hold rtp packet with metadata for sender side.
+class RtpPacketToSend : public rtp::Packet {
+ public:
+ explicit RtpPacketToSend(const ExtensionManager* extensions)
+ : Packet(extensions) {}
+ RtpPacketToSend(const ExtensionManager* extensions, size_t capacity)
+ : Packet(extensions, capacity) {}
+
+ // Time in local time base as close as it can to frame capture time.
+ int64_t capture_time_ms() const { return capture_time_ms_; }
+ void set_capture_time_ms(int64_t time) { capture_time_ms_ = time; }
+
+ private:
+ int64_t capture_time_ms_ = 0;
+};
+
+} // namespace webrtc
+#endif // WEBRTC_MODULES_RTP_RTCP_SOURCE_RTP_PACKET_TO_SEND_H_
diff --git a/webrtc/modules/rtp_rtcp/source/rtp_packet_unittest.cc b/webrtc/modules/rtp_rtcp/source/rtp_packet_unittest.cc
new file mode 100644
index 0000000..b992d2d
--- /dev/null
+++ b/webrtc/modules/rtp_rtcp/source/rtp_packet_unittest.cc
@@ -0,0 +1,252 @@
+/*
+ * 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/rtp_packet_received.h"
+#include "webrtc/modules/rtp_rtcp/source/rtp_packet_to_send.h"
+
+#include "testing/gmock/include/gmock/gmock.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#include "webrtc/base/random.h"
+#include "webrtc/modules/rtp_rtcp/source/rtp_header_extensions.h"
+#include "webrtc/modules/rtp_rtcp/source/rtp_header_extension.h"
+
+using testing::ElementsAreArray;
+using testing::make_tuple;
+
+namespace webrtc {
+namespace {
+constexpr int8_t kPayloadType = 100;
+constexpr uint32_t kSsrc = 0x12345678;
+constexpr uint16_t kSeqNum = 88;
+constexpr uint32_t kTimestamp = 0x65431278;
+constexpr uint8_t kTransmissionOffsetExtensionId = 1;
+constexpr uint8_t kAudioLevelExtensionId = 9;
+constexpr int32_t kTimeOffset = 0x56ce;
+constexpr bool kVoiceActive = true;
+constexpr uint8_t kAudioLevel = 0x5a;
+constexpr size_t kMaxPaddingSize = 224u;
+constexpr uint8_t kMinimumPacket[] = {
+ 0x80, kPayloadType, 0x00, kSeqNum,
+ 0x65, 0x43, 0x12, 0x78,
+ 0x12, 0x34, 0x56, 0x78};
+constexpr uint8_t kPacketWithTO[] = {
+ 0x90, kPayloadType, 0x00, kSeqNum,
+ 0x65, 0x43, 0x12, 0x78,
+ 0x12, 0x34, 0x56, 0x78,
+ 0xbe, 0xde, 0x00, 0x01,
+ 0x12, 0x00, 0x56, 0xce};
+
+constexpr uint8_t kPacketWithTOAndAL[] = {
+ 0x90, kPayloadType, 0x00, kSeqNum,
+ 0x65, 0x43, 0x12, 0x78,
+ 0x12, 0x34, 0x56, 0x78,
+ 0xbe, 0xde, 0x00, 0x02,
+ 0x12, 0x00, 0x56, 0xce,
+ 0x90, 0x80|kAudioLevel, 0x00, 0x00};
+
+constexpr uint32_t kCsrcs[] = {0x34567890, 0x32435465};
+constexpr uint8_t kPayload[] = {'p', 'a', 'y', 'l', 'o', 'a', 'd'};
+constexpr uint8_t kPacketPaddingSize = 8;
+constexpr uint8_t kPacket[] = {
+ 0xb2, kPayloadType, 0x00, kSeqNum,
+ 0x65, 0x43, 0x12, 0x78,
+ 0x12, 0x34, 0x56, 0x78,
+ 0x34, 0x56, 0x78, 0x90,
+ 0x32, 0x43, 0x54, 0x65,
+ 0xbe, 0xde, 0x00, 0x01,
+ 0x12, 0x00, 0x56, 0xce,
+ 'p', 'a', 'y', 'l', 'o', 'a', 'd',
+ 'p', 'a', 'd', 'd', 'i', 'n', 'g', kPacketPaddingSize};
+
+} // namespace
+
+TEST(RtpPacketTest, CreateMinimum) {
+ RtpPacketToSend packet(nullptr);
+ packet.SetPayloadType(kPayloadType);
+ packet.SetSequenceNumber(kSeqNum);
+ packet.SetTimestamp(kTimestamp);
+ packet.SetSsrc(kSsrc);
+ EXPECT_THAT(kMinimumPacket, ElementsAreArray(packet.data(), packet.size()));
+}
+
+TEST(RtpPacketTest, CreateWithExtension) {
+ RtpPacketToSend::ExtensionManager extensions;
+ extensions.Register(kRtpExtensionTransmissionTimeOffset,
+ kTransmissionOffsetExtensionId);
+ RtpPacketToSend packet(&extensions);
+ packet.SetPayloadType(kPayloadType);
+ packet.SetSequenceNumber(kSeqNum);
+ packet.SetTimestamp(kTimestamp);
+ packet.SetSsrc(kSsrc);
+ packet.SetExtension<TransmissionOffset>(kTimeOffset);
+ EXPECT_THAT(kPacketWithTO, ElementsAreArray(packet.data(), packet.size()));
+}
+
+TEST(RtpPacketTest, CreateWith2Extensions) {
+ RtpPacketToSend::ExtensionManager extensions;
+ extensions.Register(kRtpExtensionTransmissionTimeOffset,
+ kTransmissionOffsetExtensionId);
+ extensions.Register(kRtpExtensionAudioLevel, kAudioLevelExtensionId);
+ RtpPacketToSend packet(&extensions);
+ packet.SetPayloadType(kPayloadType);
+ packet.SetSequenceNumber(kSeqNum);
+ packet.SetTimestamp(kTimestamp);
+ packet.SetSsrc(kSsrc);
+ packet.SetExtension<TransmissionOffset>(kTimeOffset);
+ packet.SetExtension<AudioLevel>(kVoiceActive, kAudioLevel);
+ EXPECT_THAT(kPacketWithTOAndAL,
+ ElementsAreArray(packet.data(), packet.size()));
+}
+
+TEST(RtpPacketTest, SetReservedExtensionsAfterPayload) {
+ const size_t kPayloadSize = 4;
+ RtpPacketToSend::ExtensionManager extensions;
+ extensions.Register(kRtpExtensionTransmissionTimeOffset,
+ kTransmissionOffsetExtensionId);
+ extensions.Register(kRtpExtensionAudioLevel, kAudioLevelExtensionId);
+ RtpPacketToSend packet(&extensions);
+
+ EXPECT_TRUE(packet.ReserveExtension<TransmissionOffset>());
+ packet.AllocatePayload(kPayloadSize);
+ // Can't set extension after payload.
+ EXPECT_FALSE(packet.SetExtension<AudioLevel>(kVoiceActive, kAudioLevel));
+ // Unless reserved.
+ EXPECT_TRUE(packet.SetExtension<TransmissionOffset>(kTimeOffset));
+}
+
+TEST(RtpPacketTest, CreatePurePadding) {
+ const size_t kPaddingSize = kMaxPaddingSize - 1;
+ RtpPacketToSend packet(nullptr, 12 + kPaddingSize);
+ packet.SetPayloadType(kPayloadType);
+ packet.SetSequenceNumber(kSeqNum);
+ packet.SetTimestamp(kTimestamp);
+ packet.SetSsrc(kSsrc);
+ Random random(0x123456789);
+
+ EXPECT_LT(packet.size(), packet.capacity());
+ EXPECT_FALSE(packet.SetPadding(kPaddingSize + 1, &random));
+ EXPECT_TRUE(packet.SetPadding(kPaddingSize, &random));
+ EXPECT_EQ(packet.size(), packet.capacity());
+}
+
+TEST(RtpPacketTest, CreateUnalignedPadding) {
+ const size_t kPayloadSize = 3; // Make padding start at unaligned address.
+ RtpPacketToSend packet(nullptr, 12 + kPayloadSize + kMaxPaddingSize);
+ packet.SetPayloadType(kPayloadType);
+ packet.SetSequenceNumber(kSeqNum);
+ packet.SetTimestamp(kTimestamp);
+ packet.SetSsrc(kSsrc);
+ packet.AllocatePayload(kPayloadSize);
+ Random r(0x123456789);
+
+ EXPECT_LT(packet.size(), packet.capacity());
+ EXPECT_TRUE(packet.SetPadding(kMaxPaddingSize, &r));
+ EXPECT_EQ(packet.size(), packet.capacity());
+}
+
+TEST(RtpPacketTest, ParseMinimum) {
+ RtpPacketReceived packet;
+ EXPECT_TRUE(packet.Parse(kMinimumPacket, sizeof(kMinimumPacket)));
+ EXPECT_EQ(kPayloadType, packet.PayloadType());
+ EXPECT_EQ(kSeqNum, packet.SequenceNumber());
+ EXPECT_EQ(kTimestamp, packet.Timestamp());
+ EXPECT_EQ(kSsrc, packet.Ssrc());
+ EXPECT_EQ(0u, packet.padding_size());
+ EXPECT_EQ(0u, packet.payload_size());
+}
+
+TEST(RtpPacketTest, ParseBuffer) {
+ rtc::Buffer unparsed(kMinimumPacket);
+ const uint8_t* raw = unparsed.data();
+
+ RtpPacketReceived packet;
+ EXPECT_TRUE(packet.Parse(std::move(unparsed)));
+ EXPECT_EQ(raw, packet.data()); // Expect packet took over the buffer.
+ EXPECT_EQ(kSeqNum, packet.SequenceNumber());
+ EXPECT_EQ(kTimestamp, packet.Timestamp());
+ EXPECT_EQ(kSsrc, packet.Ssrc());
+ EXPECT_EQ(0u, packet.padding_size());
+ EXPECT_EQ(0u, packet.payload_size());
+}
+
+TEST(RtpPacketTest, ParseWithExtension) {
+ RtpPacketToSend::ExtensionManager extensions;
+ extensions.Register(kRtpExtensionTransmissionTimeOffset,
+ kTransmissionOffsetExtensionId);
+
+ RtpPacketReceived packet(&extensions);
+ EXPECT_TRUE(packet.Parse(kPacketWithTO, sizeof(kPacketWithTO)));
+ EXPECT_EQ(kPayloadType, packet.PayloadType());
+ EXPECT_EQ(kSeqNum, packet.SequenceNumber());
+ EXPECT_EQ(kTimestamp, packet.Timestamp());
+ EXPECT_EQ(kSsrc, packet.Ssrc());
+ int32_t time_offset;
+ EXPECT_TRUE(packet.GetExtension<TransmissionOffset>(&time_offset));
+ EXPECT_EQ(kTimeOffset, time_offset);
+ EXPECT_EQ(0u, packet.payload_size());
+ EXPECT_EQ(0u, packet.padding_size());
+}
+
+TEST(RtpPacketTest, ParseWith2Extensions) {
+ RtpPacketToSend::ExtensionManager extensions;
+ extensions.Register(kRtpExtensionTransmissionTimeOffset,
+ kTransmissionOffsetExtensionId);
+ extensions.Register(kRtpExtensionAudioLevel, kAudioLevelExtensionId);
+ RtpPacketReceived packet(&extensions);
+ EXPECT_TRUE(packet.Parse(kPacketWithTOAndAL, sizeof(kPacketWithTOAndAL)));
+ int32_t time_offset;
+ EXPECT_TRUE(packet.GetExtension<TransmissionOffset>(&time_offset));
+ EXPECT_EQ(kTimeOffset, time_offset);
+ bool voice_active;
+ uint8_t audio_level;
+ EXPECT_TRUE(packet.GetExtension<AudioLevel>(&voice_active, &audio_level));
+ EXPECT_EQ(kVoiceActive, voice_active);
+ EXPECT_EQ(kAudioLevel, audio_level);
+}
+
+TEST(RtpPacketTest, ParseWithAllFeatures) {
+ RtpPacketToSend::ExtensionManager extensions;
+ extensions.Register(kRtpExtensionTransmissionTimeOffset,
+ kTransmissionOffsetExtensionId);
+ RtpPacketReceived packet(&extensions);
+ EXPECT_TRUE(packet.Parse(kPacket, sizeof(kPacket)));
+ EXPECT_EQ(kPayloadType, packet.PayloadType());
+ EXPECT_EQ(kSeqNum, packet.SequenceNumber());
+ EXPECT_EQ(kTimestamp, packet.Timestamp());
+ EXPECT_EQ(kSsrc, packet.Ssrc());
+ EXPECT_THAT(packet.Csrcs(), ElementsAreArray(kCsrcs));
+ EXPECT_THAT(make_tuple(packet.payload(), packet.payload_size()),
+ ElementsAreArray(kPayload));
+ EXPECT_EQ(kPacketPaddingSize, packet.padding_size());
+ int32_t time_offset;
+ EXPECT_TRUE(packet.GetExtension<TransmissionOffset>(&time_offset));
+}
+
+TEST(RtpPacketTest, ParseWithExtensionDelayed) {
+ RtpPacketReceived packet;
+ EXPECT_TRUE(packet.Parse(kPacketWithTO, sizeof(kPacketWithTO)));
+ EXPECT_EQ(kPayloadType, packet.PayloadType());
+ EXPECT_EQ(kSeqNum, packet.SequenceNumber());
+ EXPECT_EQ(kTimestamp, packet.Timestamp());
+ EXPECT_EQ(kSsrc, packet.Ssrc());
+
+ RtpPacketToSend::ExtensionManager extensions;
+ extensions.Register(kRtpExtensionTransmissionTimeOffset,
+ kTransmissionOffsetExtensionId);
+
+ int32_t time_offset;
+ EXPECT_FALSE(packet.GetExtension<TransmissionOffset>(&time_offset));
+ packet.IdentifyExtensions(&extensions);
+ EXPECT_TRUE(packet.GetExtension<TransmissionOffset>(&time_offset));
+ EXPECT_EQ(kTimeOffset, time_offset);
+ EXPECT_EQ(0u, packet.payload_size());
+ EXPECT_EQ(0u, packet.padding_size());
+}
+
+} // namespace webrtc
diff --git a/webrtc/test/fuzzers/BUILD.gn b/webrtc/test/fuzzers/BUILD.gn
index c46cc1e..3e59339 100644
--- a/webrtc/test/fuzzers/BUILD.gn
+++ b/webrtc/test/fuzzers/BUILD.gn
@@ -75,6 +75,15 @@
]
}
+webrtc_fuzzer_test("rtp_packet_fuzzer") {
+ sources = [
+ "rtp_packet_fuzzer.cc",
+ ]
+ deps = [
+ "../../modules/rtp_rtcp/",
+ ]
+}
+
source_set("audio_decoder_fuzzer") {
public_configs = [ "../..:common_inherited_config" ]
sources = [
diff --git a/webrtc/test/fuzzers/rtp_packet_fuzzer.cc b/webrtc/test/fuzzers/rtp_packet_fuzzer.cc
new file mode 100644
index 0000000..a9efdb9
--- /dev/null
+++ b/webrtc/test/fuzzers/rtp_packet_fuzzer.cc
@@ -0,0 +1,29 @@
+/*
+ * 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/rtp_packet_received.h"
+
+namespace webrtc {
+
+void FuzzOneInput(const uint8_t* data, size_t size) {
+ RtpPacketReceived packet;
+
+ packet.Parse(data, size);
+
+ // Call packet accessors because they have extra checks.
+ packet.Marker();
+ packet.PayloadType();
+ packet.SequenceNumber();
+ packet.Timestamp();
+ packet.Ssrc();
+ packet.Csrcs();
+}
+
+} // namespace webrtc
+