RtpPacket class introduced.
BUG=webrtc:1994, webrtc:5261 Review URL: https://codereview.webrtc.org/1841453004 Cr-Commit-Position: refs/heads/master@{#12444}
This commit is contained in:
parent
2ddf09397f
commit
1edb7ab7bd
@ -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',
|
||||
|
||||
@ -118,9 +118,15 @@ source_set("rtp_rtcp") {
|
||||
"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",
|
||||
|
||||
@ -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',
|
||||
|
||||
@ -112,6 +112,14 @@ int32_t RtpHeaderExtensionMap::GetType(const uint8_t id,
|
||||
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 @@ int32_t RtpHeaderExtensionMap::GetId(const RTPExtensionType type,
|
||||
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;
|
||||
|
||||
@ -70,6 +70,8 @@ struct HeaderExtension {
|
||||
|
||||
class RtpHeaderExtensionMap {
|
||||
public:
|
||||
static constexpr RTPExtensionType kInvalidType = kRtpExtensionNone;
|
||||
static constexpr uint8_t kInvalidId = 0;
|
||||
RtpHeaderExtensionMap();
|
||||
~RtpHeaderExtensionMap();
|
||||
|
||||
@ -89,8 +91,12 @@ class RtpHeaderExtensionMap {
|
||||
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.
|
||||
|
||||
203
webrtc/modules/rtp_rtcp/source/rtp_header_extensions.cc
Normal file
203
webrtc/modules/rtp_rtcp/source/rtp_header_extensions.cc
Normal file
@ -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
|
||||
75
webrtc/modules/rtp_rtcp/source/rtp_header_extensions.h
Normal file
75
webrtc/modules/rtp_rtcp/source/rtp_header_extensions.h
Normal file
@ -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_
|
||||
509
webrtc/modules/rtp_rtcp/source/rtp_packet.cc
Normal file
509
webrtc/modules/rtp_rtcp/source/rtp_packet.cc
Normal file
@ -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
|
||||
186
webrtc/modules/rtp_rtcp/source/rtp_packet.h
Normal file
186
webrtc/modules/rtp_rtcp/source/rtp_packet.h
Normal file
@ -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_
|
||||
56
webrtc/modules/rtp_rtcp/source/rtp_packet_received.h
Normal file
56
webrtc/modules/rtp_rtcp/source/rtp_packet_received.h
Normal file
@ -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_
|
||||
33
webrtc/modules/rtp_rtcp/source/rtp_packet_to_send.h
Normal file
33
webrtc/modules/rtp_rtcp/source/rtp_packet_to_send.h
Normal file
@ -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_
|
||||
252
webrtc/modules/rtp_rtcp/source/rtp_packet_unittest.cc
Normal file
252
webrtc/modules/rtp_rtcp/source/rtp_packet_unittest.cc
Normal file
@ -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
|
||||
@ -75,6 +75,15 @@ webrtc_fuzzer_test("rtcp_receiver_fuzzer") {
|
||||
]
|
||||
}
|
||||
|
||||
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 = [
|
||||
|
||||
29
webrtc/test/fuzzers/rtp_packet_fuzzer.cc
Normal file
29
webrtc/test/fuzzers/rtp_packet_fuzzer.cc
Normal file
@ -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
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user