RtpPacketHistory rewritten to use RtpPacket class.

RtpSender updated to use new version of RtpPacketHistory.

BUG=webrtc:5261
R=asapersson@webrtc.org

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

Cr-Commit-Position: refs/heads/master@{#13626}
This commit is contained in:
Danil Chapovalov 2016-08-03 18:27:40 +02:00
parent 6b42cef98d
commit 31e4e806b1
12 changed files with 469 additions and 774 deletions

View File

@ -124,14 +124,14 @@ bool TransmissionOffset::IsSupportedFor(MediaType type) {
return false;
}
bool TransmissionOffset::Parse(const uint8_t* data, int32_t* value) {
*value = ByteReader<int32_t, 3>::ReadBigEndian(data);
bool TransmissionOffset::Parse(const uint8_t* data, int32_t* rtp_time) {
*rtp_time = 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);
bool TransmissionOffset::Write(uint8_t* data, int32_t rtp_time) {
RTC_DCHECK_LE(rtp_time, 0x00ffffff);
ByteWriter<int32_t, 3>::WriteBigEndian(data, rtp_time);
return true;
}

View File

@ -45,8 +45,8 @@ class TransmissionOffset {
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);
static bool Parse(const uint8_t* data, int32_t* rtp_time);
static bool Write(uint8_t* data, int32_t rtp_time);
};
class TransportSequenceNumber {

View File

@ -78,18 +78,19 @@ bool Packet::Parse(const uint8_t* buffer, size_t buffer_size) {
Clear();
return false;
}
RTC_DCHECK_EQ(size(), buffer_size);
buffer_.SetData(buffer, buffer_size);
RTC_DCHECK_EQ(size(), buffer_size);
return true;
}
bool Packet::Parse(rtc::Buffer buffer) {
if (!ParseBuffer(buffer.data(), buffer.size())) {
bool Packet::Parse(rtc::CopyOnWriteBuffer buffer) {
if (!ParseBuffer(buffer.cdata(), buffer.size())) {
Clear();
return false;
}
RTC_DCHECK_EQ(size(), buffer.size());
size_t buffer_size = buffer.size();
buffer_ = std::move(buffer);
RTC_DCHECK_EQ(size(), buffer_size);
return true;
}
@ -174,16 +175,22 @@ const uint8_t* Packet::payload() const {
return data() + payload_offset_;
}
rtc::CopyOnWriteBuffer Packet::Buffer() const {
return buffer_;
}
size_t Packet::capacity() const {
return buffer_.size();
return buffer_.capacity();
}
size_t Packet::size() const {
return payload_offset_ + payload_size_ + padding_size_;
size_t ret = payload_offset_ + payload_size_ + padding_size_;
RTC_DCHECK_EQ(buffer_.size(), ret);
return ret;
}
const uint8_t* Packet::data() const {
return buffer_.data();
return buffer_.cdata();
}
size_t Packet::FreeCapacity() const {
@ -194,7 +201,7 @@ size_t Packet::MaxPayloadSize() const {
return capacity() - payload_offset_;
}
void Packet::CopyHeader(const Packet& packet) {
void Packet::CopyHeaderFrom(const Packet& packet) {
RTC_DCHECK_GE(capacity(), packet.headers_size());
marker_ = packet.marker_;
@ -257,6 +264,7 @@ void Packet::SetCsrcs(const std::vector<uint32_t>& csrcs) {
ByteWriter<uint32_t>::WriteBigEndian(WriteAt(offset), csrc);
offset += 4;
}
buffer_.SetSize(payload_offset_);
}
uint8_t* Packet::AllocatePayload(size_t size_bytes) {
@ -266,6 +274,7 @@ uint8_t* Packet::AllocatePayload(size_t size_bytes) {
return nullptr;
}
payload_size_ = size_bytes;
buffer_.SetSize(payload_offset_ + payload_size_);
return WriteAt(payload_offset_);
}
@ -273,6 +282,7 @@ void Packet::SetPayloadSize(size_t size_bytes) {
RTC_DCHECK_EQ(padding_size_, 0u);
RTC_DCHECK_LE(size_bytes, payload_size_);
payload_size_ = size_bytes;
buffer_.SetSize(payload_offset_ + payload_size_);
}
bool Packet::SetPadding(uint8_t size_bytes, Random* random) {
@ -284,6 +294,7 @@ bool Packet::SetPadding(uint8_t size_bytes, Random* random) {
return false;
}
padding_size_ = size_bytes;
buffer_.SetSize(payload_offset_ + payload_size_ + padding_size_);
if (padding_size_ > 0) {
size_t padding_offset = payload_offset_ + payload_size_;
size_t padding_end = padding_offset + padding_size_;
@ -311,6 +322,7 @@ void Packet::Clear() {
extensions_size_ = 0;
memset(WriteAt(0), 0, kFixedHeaderSize);
buffer_.SetSize(kFixedHeaderSize);
WriteAt(0, kRtpVersion << 6);
}
@ -497,6 +509,7 @@ bool Packet::AllocateExtension(ExtensionType type,
memset(WriteAt(extensions_offset + extensions_size_), 0,
extension_padding_size);
payload_offset_ = extensions_offset + 4 * extensions_words;
buffer_.SetSize(payload_offset_);
return true;
}

View File

@ -13,8 +13,7 @@
#include <vector>
#include "webrtc/base/basictypes.h"
#include "webrtc/base/buffer.h"
#include "webrtc/base/constructormagic.h"
#include "webrtc/base/copyonwritebuffer.h"
#include "webrtc/modules/rtp_rtcp/include/rtp_rtcp_defines.h"
namespace webrtc {
@ -33,7 +32,7 @@ class Packet {
bool Parse(const uint8_t* buffer, size_t size);
// Parse and move given buffer into Packet.
bool Parse(rtc::Buffer packet);
bool Parse(rtc::CopyOnWriteBuffer packet);
// Maps parsed extensions to their types to allow use of GetExtension.
// Used after parsing when |extensions| can't be provided until base rtp
@ -60,6 +59,7 @@ class Packet {
const uint8_t* payload() const;
// Buffer.
rtc::CopyOnWriteBuffer Buffer() const;
size_t capacity() const;
size_t size() const;
const uint8_t* data() const;
@ -70,7 +70,7 @@ class Packet {
void Clear();
// Header setters.
void CopyHeader(const Packet& packet);
void CopyHeaderFrom(const Packet& packet);
void SetMarker(bool marker_bit);
void SetPayloadType(uint8_t payload_type);
void SetSequenceNumber(uint16_t seq_no);
@ -103,9 +103,12 @@ class Packet {
// Adding and getting extensions will fail until |extensions| is
// provided via constructor or IdentifyExtensions function.
explicit Packet(const ExtensionManager* extensions);
Packet(const Packet&) = default;
Packet(const ExtensionManager* extensions, size_t capacity);
virtual ~Packet();
Packet& operator=(const Packet&) = default;
private:
struct ExtensionInfo {
ExtensionType type;
@ -152,9 +155,9 @@ class Packet {
uint8_t num_extensions_ = 0;
ExtensionInfo extension_entries_[kMaxExtensionHeaders];
uint16_t extensions_size_ = 0; // Unaligned.
rtc::Buffer buffer_;
rtc::CopyOnWriteBuffer buffer_;
RTC_DISALLOW_IMPLICIT_CONSTRUCTORS(Packet);
Packet() = delete;
};
template <typename Extension, typename... Values>

View File

@ -10,31 +10,26 @@
#include "webrtc/modules/rtp_rtcp/source/rtp_packet_history.h"
#include <assert.h>
#include <stdlib.h>
#include <string.h> // memset
#include <algorithm>
#include <limits>
#include <set>
#include "webrtc/base/checks.h"
#include "webrtc/base/logging.h"
#include "webrtc/modules/rtp_rtcp/source/rtp_utility.h"
#include "webrtc/modules/rtp_rtcp/source/rtp_packet_to_send.h"
#include "webrtc/system_wrappers/include/clock.h"
namespace webrtc {
namespace {
constexpr size_t kMinPacketRequestBytes = 50;
} // namespace
constexpr size_t RtpPacketHistory::kMaxCapacity;
static const int kMinPacketRequestBytes = 50;
RtpPacketHistory::RtpPacketHistory(Clock* clock)
: clock_(clock), store_(false), prev_index_(0) {}
RTPPacketHistory::RTPPacketHistory(Clock* clock)
: clock_(clock),
store_(false),
prev_index_(0) {}
RtpPacketHistory::~RtpPacketHistory() {}
RTPPacketHistory::~RTPPacketHistory() {
}
void RTPPacketHistory::SetStorePacketsStatus(bool enable,
void RtpPacketHistory::SetStorePacketsStatus(bool enable,
uint16_t number_to_store) {
rtc::CritScope cs(&critsect_);
if (enable) {
@ -42,21 +37,21 @@ void RTPPacketHistory::SetStorePacketsStatus(bool enable,
LOG(LS_WARNING) << "Purging packet history in order to re-set status.";
Free();
}
assert(!store_);
RTC_DCHECK(!store_);
Allocate(number_to_store);
} else {
Free();
}
}
void RTPPacketHistory::Allocate(size_t number_to_store) {
assert(number_to_store > 0);
assert(number_to_store <= kMaxHistoryCapacity);
void RtpPacketHistory::Allocate(size_t number_to_store) {
RTC_DCHECK_GT(number_to_store, 0u);
RTC_DCHECK_LE(number_to_store, kMaxCapacity);
store_ = true;
stored_packets_.resize(number_to_store);
}
void RTPPacketHistory::Free() {
void RtpPacketHistory::Free() {
if (!store_) {
return;
}
@ -67,40 +62,29 @@ void RTPPacketHistory::Free() {
prev_index_ = 0;
}
bool RTPPacketHistory::StorePackets() const {
bool RtpPacketHistory::StorePackets() const {
rtc::CritScope cs(&critsect_);
return store_;
}
int32_t RTPPacketHistory::PutRTPPacket(const uint8_t* packet,
size_t packet_length,
int64_t capture_time_ms,
StorageType type) {
void RtpPacketHistory::PutRtpPacket(std::unique_ptr<RtpPacketToSend> packet,
StorageType type,
bool sent) {
RTC_DCHECK(packet);
rtc::CritScope cs(&critsect_);
if (!store_) {
return 0;
return;
}
assert(packet);
assert(packet_length > 3);
if (packet_length > IP_PACKET_SIZE) {
LOG(LS_WARNING) << "Failed to store RTP packet with length: "
<< packet_length;
return -1;
}
const uint16_t seq_num = (packet[2] << 8) + packet[3];
// If index we're about to overwrite contains a packet that has not
// yet been sent (probably pending in paced sender), we need to expand
// the buffer.
if (stored_packets_[prev_index_].length > 0 &&
if (stored_packets_[prev_index_].packet &&
stored_packets_[prev_index_].send_time == 0) {
size_t current_size = static_cast<uint16_t>(stored_packets_.size());
if (current_size < kMaxHistoryCapacity) {
if (current_size < kMaxCapacity) {
size_t expanded_size = std::max(current_size * 3 / 2, current_size + 1);
expanded_size = std::min(expanded_size, kMaxHistoryCapacity);
expanded_size = std::min(expanded_size, kMaxCapacity);
Allocate(expanded_size);
// Causes discontinuity, but that's OK-ish. FindSeqNum() will still work,
// but may be slower - at least until buffer has wrapped around once.
@ -108,91 +92,48 @@ int32_t RTPPacketHistory::PutRTPPacket(const uint8_t* packet,
}
}
// Store packet
// TODO(sprang): Overhaul this class and get rid of this copy step.
// (Finally introduce the RtpPacket class?)
memcpy(stored_packets_[prev_index_].data, packet, packet_length);
stored_packets_[prev_index_].length = packet_length;
stored_packets_[prev_index_].sequence_number = seq_num;
stored_packets_[prev_index_].time_ms =
(capture_time_ms > 0) ? capture_time_ms : clock_->TimeInMilliseconds();
stored_packets_[prev_index_].send_time = 0; // Packet not sent.
// Store packet.
if (packet->capture_time_ms() <= 0)
packet->set_capture_time_ms(clock_->TimeInMilliseconds());
stored_packets_[prev_index_].sequence_number = packet->SequenceNumber();
stored_packets_[prev_index_].send_time =
(sent ? clock_->TimeInMilliseconds() : 0);
stored_packets_[prev_index_].storage_type = type;
stored_packets_[prev_index_].has_been_retransmitted = false;
stored_packets_[prev_index_].packet = std::move(packet);
++prev_index_;
if (prev_index_ >= stored_packets_.size()) {
prev_index_ = 0;
}
return 0;
}
bool RTPPacketHistory::HasRTPPacket(uint16_t sequence_number) const {
bool RtpPacketHistory::HasRtpPacket(uint16_t sequence_number) const {
rtc::CritScope cs(&critsect_);
if (!store_) {
return false;
}
int32_t index = 0;
bool found = FindSeqNum(sequence_number, &index);
if (!found) {
return false;
}
if (stored_packets_[index].length == 0) {
// Invalid length.
return false;
}
return true;
int unused_index = 0;
return FindSeqNum(sequence_number, &unused_index);
}
bool RTPPacketHistory::SetSent(uint16_t sequence_number) {
std::unique_ptr<RtpPacketToSend> RtpPacketHistory::GetPacketAndSetSendTime(
uint16_t sequence_number,
int64_t min_elapsed_time_ms,
bool retransmit) {
rtc::CritScope cs(&critsect_);
if (!store_) {
return false;
return nullptr;
}
int32_t index = 0;
bool found = FindSeqNum(sequence_number, &index);
if (!found) {
return false;
}
// Send time already set.
if (stored_packets_[index].send_time != 0) {
return false;
}
stored_packets_[index].send_time = clock_->TimeInMilliseconds();
return true;
}
bool RTPPacketHistory::GetPacketAndSetSendTime(uint16_t sequence_number,
int64_t min_elapsed_time_ms,
bool retransmit,
uint8_t* packet,
size_t* packet_length,
int64_t* stored_time_ms) {
rtc::CritScope cs(&critsect_);
RTC_CHECK_GE(*packet_length, static_cast<size_t>(IP_PACKET_SIZE));
if (!store_)
return false;
int32_t index = 0;
bool found = FindSeqNum(sequence_number, &index);
if (!found) {
int index = 0;
if (!FindSeqNum(sequence_number, &index)) {
LOG(LS_WARNING) << "No match for getting seqNum " << sequence_number;
return false;
}
size_t length = stored_packets_[index].length;
assert(length <= IP_PACKET_SIZE);
if (length == 0) {
LOG(LS_WARNING) << "No match for getting seqNum " << sequence_number
<< ", len " << length;
return false;
return nullptr;
}
RTC_DCHECK_EQ(sequence_number,
stored_packets_[index].packet->SequenceNumber());
// Verify elapsed time since last retrieve, but only for retransmissions and
// always send packet upon first retransmission request.
@ -200,59 +141,45 @@ bool RTPPacketHistory::GetPacketAndSetSendTime(uint16_t sequence_number,
if (min_elapsed_time_ms > 0 && retransmit &&
stored_packets_[index].has_been_retransmitted &&
((now - stored_packets_[index].send_time) < min_elapsed_time_ms)) {
return false;
return nullptr;
}
if (retransmit) {
if (stored_packets_[index].storage_type == kDontRetransmit) {
// No bytes copied since this packet shouldn't be retransmitted or is
// of zero size.
return false;
// No bytes copied since this packet shouldn't be retransmitted.
return nullptr;
}
stored_packets_[index].has_been_retransmitted = true;
}
stored_packets_[index].send_time = clock_->TimeInMilliseconds();
GetPacket(index, packet, packet_length, stored_time_ms);
return true;
return GetPacket(index);
}
void RTPPacketHistory::GetPacket(int index,
uint8_t* packet,
size_t* packet_length,
int64_t* stored_time_ms) const {
// Get packet.
size_t length = stored_packets_[index].length;
memcpy(packet, stored_packets_[index].data, length);
*packet_length = length;
*stored_time_ms = stored_packets_[index].time_ms;
std::unique_ptr<RtpPacketToSend> RtpPacketHistory::GetPacket(int index) const {
const RtpPacketToSend& stored = *stored_packets_[index].packet;
return std::unique_ptr<RtpPacketToSend>(new RtpPacketToSend(stored));
}
bool RTPPacketHistory::GetBestFittingPacket(uint8_t* packet,
size_t* packet_length,
int64_t* stored_time_ms) {
std::unique_ptr<RtpPacketToSend> RtpPacketHistory::GetBestFittingPacket(
size_t packet_length) const {
rtc::CritScope cs(&critsect_);
if (!store_)
return false;
int index = FindBestFittingPacket(*packet_length);
return nullptr;
int index = FindBestFittingPacket(packet_length);
if (index < 0)
return false;
GetPacket(index, packet, packet_length, stored_time_ms);
return true;
return nullptr;
return GetPacket(index);
}
// private, lock should already be taken
bool RTPPacketHistory::FindSeqNum(uint16_t sequence_number,
int32_t* index) const {
uint16_t temp_sequence_number = 0;
bool RtpPacketHistory::FindSeqNum(uint16_t sequence_number, int* index) const {
if (prev_index_ > 0) {
*index = prev_index_ - 1;
temp_sequence_number = stored_packets_[*index].sequence_number;
} else {
*index = stored_packets_.size() - 1;
temp_sequence_number = stored_packets_[*index].sequence_number; // wrap
*index = stored_packets_.size() - 1; // Wrap.
}
uint16_t temp_sequence_number = stored_packets_[*index].sequence_number;
int32_t idx = (prev_index_ - 1) - (temp_sequence_number - sequence_number);
int idx = *index - (temp_sequence_number - sequence_number);
if (idx >= 0 && idx < static_cast<int>(stored_packets_.size())) {
*index = idx;
temp_sequence_number = stored_packets_[*index].sequence_number;
@ -268,24 +195,21 @@ bool RTPPacketHistory::FindSeqNum(uint16_t sequence_number,
}
}
}
if (temp_sequence_number == sequence_number) {
// We found a match.
return true;
}
return false;
return temp_sequence_number == sequence_number &&
stored_packets_[*index].packet;
}
int RTPPacketHistory::FindBestFittingPacket(size_t size) const {
int RtpPacketHistory::FindBestFittingPacket(size_t size) const {
if (size < kMinPacketRequestBytes || stored_packets_.empty())
return -1;
size_t min_diff = std::numeric_limits<size_t>::max();
int best_index = -1; // Returned unchanged if we don't find anything.
for (size_t i = 0; i < stored_packets_.size(); ++i) {
if (stored_packets_[i].length == 0)
if (!stored_packets_[i].packet)
continue;
size_t diff = (stored_packets_[i].length > size)
? (stored_packets_[i].length - size)
: (size - stored_packets_[i].length);
size_t stored_size = stored_packets_[i].packet->size();
size_t diff =
(stored_size > size) ? (stored_size - size) : (size - stored_size);
if (diff < min_diff) {
min_diff = diff;
best_index = static_cast<int>(i);
@ -294,6 +218,4 @@ int RTPPacketHistory::FindBestFittingPacket(size_t size) const {
return best_index;
}
RTPPacketHistory::StoredPacket::StoredPacket() {}
} // namespace webrtc

View File

@ -6,99 +6,80 @@
* 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.
*
* Class for storing RTP packets.
*/
#ifndef WEBRTC_MODULES_RTP_RTCP_SOURCE_RTP_PACKET_HISTORY_H_
#define WEBRTC_MODULES_RTP_RTCP_SOURCE_RTP_PACKET_HISTORY_H_
#include <memory>
#include <vector>
#include "webrtc/base/constructormagic.h"
#include "webrtc/base/criticalsection.h"
#include "webrtc/base/thread_annotations.h"
#include "webrtc/modules/include/module_common_types.h"
#include "webrtc/modules/rtp_rtcp/include/rtp_rtcp_defines.h"
#include "webrtc/typedefs.h"
namespace webrtc {
class Clock;
class RtpPacketToSend;
static const size_t kMaxHistoryCapacity = 9600;
class RTPPacketHistory {
class RtpPacketHistory {
public:
explicit RTPPacketHistory(Clock* clock);
~RTPPacketHistory();
static constexpr size_t kMaxCapacity = 9600;
explicit RtpPacketHistory(Clock* clock);
~RtpPacketHistory();
void SetStorePacketsStatus(bool enable, uint16_t number_to_store);
bool StorePackets() const;
// Stores RTP packet.
int32_t PutRTPPacket(const uint8_t* packet,
size_t packet_length,
int64_t capture_time_ms,
StorageType type);
void PutRtpPacket(std::unique_ptr<RtpPacketToSend> packet,
StorageType type,
bool sent);
// Gets stored RTP packet corresponding to the input sequence number.
// The packet is copied to the buffer pointed to by ptr_rtp_packet.
// The rtp_packet_length should show the available buffer size.
// Returns true if packet is found.
// packet_length: returns the copied packet length on success.
// min_elapsed_time_ms: the minimum time that must have elapsed since the last
// time the packet was resent (parameter is ignored if set to zero).
// If the packet is found but the minimum time has not elapsed, no bytes are
// copied.
// stored_time_ms: returns the time when the packet was stored.
bool GetPacketAndSetSendTime(uint16_t sequence_number,
int64_t min_elapsed_time_ms,
bool retransmit,
uint8_t* packet,
size_t* packet_length,
int64_t* stored_time_ms);
// Gets stored RTP packet corresponding to the input |sequence number|.
// Returns nullptr if packet is not found.
// |min_elapsed_time_ms| is the minimum time that must have elapsed since
// the last time the packet was resent (parameter is ignored if set to zero).
// If the packet is found but the minimum time has not elapsed, returns
// nullptr.
std::unique_ptr<RtpPacketToSend> GetPacketAndSetSendTime(
uint16_t sequence_number,
int64_t min_elapsed_time_ms,
bool retransmit);
bool GetBestFittingPacket(uint8_t* packet, size_t* packet_length,
int64_t* stored_time_ms);
std::unique_ptr<RtpPacketToSend> GetBestFittingPacket(
size_t packet_size) const;
bool HasRTPPacket(uint16_t sequence_number) const;
bool SetSent(uint16_t sequence_number);
bool HasRtpPacket(uint16_t sequence_number) const;
private:
void GetPacket(int index,
uint8_t* packet,
size_t* packet_length,
int64_t* stored_time_ms) const
EXCLUSIVE_LOCKS_REQUIRED(critsect_);
void Allocate(size_t number_to_store) EXCLUSIVE_LOCKS_REQUIRED(critsect_);
void Free() EXCLUSIVE_LOCKS_REQUIRED(critsect_);
void VerifyAndAllocatePacketLength(size_t packet_length, uint32_t start_index)
EXCLUSIVE_LOCKS_REQUIRED(critsect_);
bool FindSeqNum(uint16_t sequence_number, int32_t* index) const
EXCLUSIVE_LOCKS_REQUIRED(critsect_);
int FindBestFittingPacket(size_t size) const
EXCLUSIVE_LOCKS_REQUIRED(critsect_);
private:
Clock* clock_;
rtc::CriticalSection critsect_;
bool store_ GUARDED_BY(critsect_);
uint32_t prev_index_ GUARDED_BY(critsect_);
struct StoredPacket {
StoredPacket();
uint16_t sequence_number = 0;
int64_t time_ms = 0;
int64_t send_time = 0;
StorageType storage_type = kDontRetransmit;
bool has_been_retransmitted = false;
uint8_t data[IP_PACKET_SIZE];
size_t length = 0;
std::unique_ptr<RtpPacketToSend> packet;
};
std::unique_ptr<RtpPacketToSend> GetPacket(int index) const
EXCLUSIVE_LOCKS_REQUIRED(critsect_);
void Allocate(size_t number_to_store) EXCLUSIVE_LOCKS_REQUIRED(critsect_);
void Free() EXCLUSIVE_LOCKS_REQUIRED(critsect_);
bool FindSeqNum(uint16_t sequence_number, int* index) const
EXCLUSIVE_LOCKS_REQUIRED(critsect_);
int FindBestFittingPacket(size_t size) const
EXCLUSIVE_LOCKS_REQUIRED(critsect_);
Clock* clock_;
rtc::CriticalSection critsect_;
bool store_ GUARDED_BY(critsect_);
uint32_t prev_index_ GUARDED_BY(critsect_);
std::vector<StoredPacket> stored_packets_ GUARDED_BY(critsect_);
RTC_DISALLOW_IMPLICIT_CONSTRUCTORS(RtpPacketHistory);
};
} // namespace webrtc
#endif // WEBRTC_MODULES_RTP_RTCP_SOURCE_RTP_PACKET_HISTORY_H_

View File

@ -8,10 +8,13 @@
* be found in the AUTHORS file in the root of the source tree.
*/
#include "testing/gtest/include/gtest/gtest.h"
#include "webrtc/modules/rtp_rtcp/include/rtp_rtcp_defines.h"
#include "webrtc/modules/rtp_rtcp/source/rtp_packet_history.h"
#include <memory>
#include "testing/gtest/include/gtest/gtest.h"
#include "webrtc/modules/rtp_rtcp/include/rtp_rtcp_defines.h"
#include "webrtc/modules/rtp_rtcp/source/rtp_packet_to_send.h"
#include "webrtc/system_wrappers/include/clock.h"
#include "webrtc/typedefs.h"
@ -19,271 +22,200 @@ namespace webrtc {
class RtpPacketHistoryTest : public ::testing::Test {
protected:
RtpPacketHistoryTest()
: fake_clock_(123456),
hist_(new RTPPacketHistory(&fake_clock_)) {
}
~RtpPacketHistoryTest() {
delete hist_;
}
static constexpr uint16_t kSeqNum = 88;
RtpPacketHistoryTest() : fake_clock_(123456), hist_(&fake_clock_) {}
SimulatedClock fake_clock_;
RTPPacketHistory* hist_;
enum {kPayload = 127};
enum {kSsrc = 12345678};
enum {kSeqNum = 88};
enum {kTimestamp = 127};
enum {kMaxPacketLength = 1500};
uint8_t packet_[kMaxPacketLength];
uint8_t packet_out_[kMaxPacketLength];
RtpPacketHistory hist_;
void CreateRtpPacket(uint16_t seq_num, uint32_t ssrc, uint8_t payload,
uint32_t timestamp, uint8_t* array, size_t* cur_pos) {
array[(*cur_pos)++] = 0x80;
array[(*cur_pos)++] = payload;
array[(*cur_pos)++] = seq_num >> 8;
array[(*cur_pos)++] = seq_num;
array[(*cur_pos)++] = timestamp >> 24;
array[(*cur_pos)++] = timestamp >> 16;
array[(*cur_pos)++] = timestamp >> 8;
array[(*cur_pos)++] = timestamp;
array[(*cur_pos)++] = ssrc >> 24;
array[(*cur_pos)++] = ssrc >> 16;
array[(*cur_pos)++] = ssrc >> 8;
array[(*cur_pos)++] = ssrc;
std::unique_ptr<RtpPacketToSend> CreateRtpPacket(uint16_t seq_num) {
// Payload, ssrc, timestamp and extensions are irrelevant for this tests.
std::unique_ptr<RtpPacketToSend> packet(new RtpPacketToSend(nullptr));
packet->SetSequenceNumber(seq_num);
packet->set_capture_time_ms(fake_clock_.TimeInMilliseconds());
return packet;
}
};
TEST_F(RtpPacketHistoryTest, SetStoreStatus) {
EXPECT_FALSE(hist_->StorePackets());
hist_->SetStorePacketsStatus(true, 10);
EXPECT_TRUE(hist_->StorePackets());
hist_->SetStorePacketsStatus(false, 0);
EXPECT_FALSE(hist_->StorePackets());
EXPECT_FALSE(hist_.StorePackets());
hist_.SetStorePacketsStatus(true, 10);
EXPECT_TRUE(hist_.StorePackets());
hist_.SetStorePacketsStatus(false, 0);
EXPECT_FALSE(hist_.StorePackets());
}
TEST_F(RtpPacketHistoryTest, NoStoreStatus) {
EXPECT_FALSE(hist_->StorePackets());
size_t len = 0;
int64_t capture_time_ms = fake_clock_.TimeInMilliseconds();
CreateRtpPacket(kSeqNum, kSsrc, kPayload, kTimestamp, packet_, &len);
EXPECT_EQ(0, hist_->PutRTPPacket(packet_, len, capture_time_ms,
kAllowRetransmission));
EXPECT_FALSE(hist_.StorePackets());
std::unique_ptr<RtpPacketToSend> packet = CreateRtpPacket(kSeqNum);
hist_.PutRtpPacket(std::move(packet), kAllowRetransmission, false);
// Packet should not be stored.
len = kMaxPacketLength;
int64_t time;
EXPECT_FALSE(hist_->GetPacketAndSetSendTime(kSeqNum, 0, false, packet_, &len,
&time));
}
TEST_F(RtpPacketHistoryTest, PutRtpPacket_TooLargePacketLength) {
hist_->SetStorePacketsStatus(true, 10);
int64_t capture_time_ms = fake_clock_.TimeInMilliseconds();
EXPECT_EQ(-1, hist_->PutRTPPacket(packet_, kMaxPacketLength + 1,
capture_time_ms, kAllowRetransmission));
EXPECT_FALSE(hist_.GetPacketAndSetSendTime(kSeqNum, 0, false));
}
TEST_F(RtpPacketHistoryTest, GetRtpPacket_NotStored) {
hist_->SetStorePacketsStatus(true, 10);
size_t len = kMaxPacketLength;
int64_t time;
EXPECT_FALSE(hist_->GetPacketAndSetSendTime(0, 0, false, packet_, &len,
&time));
hist_.SetStorePacketsStatus(true, 10);
EXPECT_FALSE(hist_.GetPacketAndSetSendTime(0, 0, false));
}
TEST_F(RtpPacketHistoryTest, PutRtpPacket) {
hist_->SetStorePacketsStatus(true, 10);
size_t len = 0;
CreateRtpPacket(kSeqNum, kSsrc, kPayload, kTimestamp, packet_, &len);
hist_.SetStorePacketsStatus(true, 10);
std::unique_ptr<RtpPacketToSend> packet = CreateRtpPacket(kSeqNum);
EXPECT_FALSE(hist_->HasRTPPacket(kSeqNum));
int64_t capture_time_ms = fake_clock_.TimeInMilliseconds();
EXPECT_EQ(0, hist_->PutRTPPacket(packet_, len, capture_time_ms,
kAllowRetransmission));
EXPECT_TRUE(hist_->HasRTPPacket(kSeqNum));
EXPECT_FALSE(hist_.HasRtpPacket(kSeqNum));
hist_.PutRtpPacket(std::move(packet), kAllowRetransmission, false);
EXPECT_TRUE(hist_.HasRtpPacket(kSeqNum));
}
TEST_F(RtpPacketHistoryTest, GetRtpPacket) {
hist_->SetStorePacketsStatus(true, 10);
size_t len = 0;
hist_.SetStorePacketsStatus(true, 10);
int64_t capture_time_ms = 1;
CreateRtpPacket(kSeqNum, kSsrc, kPayload, kTimestamp, packet_, &len);
EXPECT_EQ(0, hist_->PutRTPPacket(packet_, len, capture_time_ms,
kAllowRetransmission));
std::unique_ptr<RtpPacketToSend> packet = CreateRtpPacket(kSeqNum);
packet->set_capture_time_ms(capture_time_ms);
rtc::CopyOnWriteBuffer buffer = packet->Buffer();
hist_.PutRtpPacket(std::move(packet), kAllowRetransmission, false);
size_t len_out = kMaxPacketLength;
int64_t time;
EXPECT_TRUE(hist_->GetPacketAndSetSendTime(kSeqNum, 0, false, packet_out_,
&len_out, &time));
EXPECT_EQ(len, len_out);
EXPECT_EQ(capture_time_ms, time);
for (size_t i = 0; i < len; i++) {
EXPECT_EQ(packet_[i], packet_out_[i]);
}
std::unique_ptr<RtpPacketToSend> packet_out =
hist_.GetPacketAndSetSendTime(kSeqNum, 0, false);
EXPECT_TRUE(packet_out);
EXPECT_EQ(buffer, packet_out->Buffer());
EXPECT_EQ(capture_time_ms, packet_out->capture_time_ms());
}
TEST_F(RtpPacketHistoryTest, NoCaptureTime) {
hist_->SetStorePacketsStatus(true, 10);
size_t len = 0;
hist_.SetStorePacketsStatus(true, 10);
fake_clock_.AdvanceTimeMilliseconds(1);
int64_t capture_time_ms = fake_clock_.TimeInMilliseconds();
CreateRtpPacket(kSeqNum, kSsrc, kPayload, kTimestamp, packet_, &len);
EXPECT_EQ(0, hist_->PutRTPPacket(packet_, len, -1, kAllowRetransmission));
std::unique_ptr<RtpPacketToSend> packet = CreateRtpPacket(kSeqNum);
packet->set_capture_time_ms(-1);
rtc::CopyOnWriteBuffer buffer = packet->Buffer();
hist_.PutRtpPacket(std::move(packet), kAllowRetransmission, false);
size_t len_out = kMaxPacketLength;
int64_t time;
EXPECT_TRUE(hist_->GetPacketAndSetSendTime(kSeqNum, 0, false, packet_out_,
&len_out, &time));
EXPECT_EQ(len, len_out);
EXPECT_EQ(capture_time_ms, time);
for (size_t i = 0; i < len; i++) {
EXPECT_EQ(packet_[i], packet_out_[i]);
}
std::unique_ptr<RtpPacketToSend> packet_out =
hist_.GetPacketAndSetSendTime(kSeqNum, 0, false);
EXPECT_TRUE(packet_out);
EXPECT_EQ(buffer, packet_out->Buffer());
EXPECT_EQ(capture_time_ms, packet_out->capture_time_ms());
}
TEST_F(RtpPacketHistoryTest, DontRetransmit) {
hist_->SetStorePacketsStatus(true, 10);
size_t len = 0;
hist_.SetStorePacketsStatus(true, 10);
int64_t capture_time_ms = fake_clock_.TimeInMilliseconds();
CreateRtpPacket(kSeqNum, kSsrc, kPayload, kTimestamp, packet_, &len);
EXPECT_EQ(
0, hist_->PutRTPPacket(packet_, len, capture_time_ms, kDontRetransmit));
std::unique_ptr<RtpPacketToSend> packet = CreateRtpPacket(kSeqNum);
rtc::CopyOnWriteBuffer buffer = packet->Buffer();
hist_.PutRtpPacket(std::move(packet), kDontRetransmit, false);
size_t len_out = kMaxPacketLength;
int64_t time;
EXPECT_TRUE(hist_->GetPacketAndSetSendTime(kSeqNum, 0, false, packet_out_,
&len_out, &time));
EXPECT_EQ(len, len_out);
EXPECT_EQ(capture_time_ms, time);
std::unique_ptr<RtpPacketToSend> packet_out;
packet_out = hist_.GetPacketAndSetSendTime(kSeqNum, 0, true);
EXPECT_FALSE(packet_out);
packet_out = hist_.GetPacketAndSetSendTime(kSeqNum, 0, false);
EXPECT_TRUE(packet_out);
EXPECT_EQ(buffer.size(), packet_out->size());
EXPECT_EQ(capture_time_ms, packet_out->capture_time_ms());
}
TEST_F(RtpPacketHistoryTest, MinResendTime) {
static const int64_t kMinRetransmitIntervalMs = 100;
hist_->SetStorePacketsStatus(true, 10);
size_t len = 0;
hist_.SetStorePacketsStatus(true, 10);
int64_t capture_time_ms = fake_clock_.TimeInMilliseconds();
CreateRtpPacket(kSeqNum, kSsrc, kPayload, kTimestamp, packet_, &len);
EXPECT_EQ(0, hist_->PutRTPPacket(packet_, len, capture_time_ms,
kAllowRetransmission));
std::unique_ptr<RtpPacketToSend> packet = CreateRtpPacket(kSeqNum);
size_t len = packet->size();
hist_.PutRtpPacket(std::move(packet), kAllowRetransmission, false);
// First transmission: TimeToSendPacket() call from pacer.
int64_t time;
len = kMaxPacketLength;
EXPECT_TRUE(
hist_->GetPacketAndSetSendTime(kSeqNum, 0, false, packet_, &len, &time));
EXPECT_TRUE(hist_.GetPacketAndSetSendTime(kSeqNum, 0, false));
fake_clock_.AdvanceTimeMilliseconds(kMinRetransmitIntervalMs);
// Time has elapsed.
len = kMaxPacketLength;
EXPECT_TRUE(hist_->GetPacketAndSetSendTime(kSeqNum, kMinRetransmitIntervalMs,
true, packet_, &len, &time));
EXPECT_GT(len, 0u);
EXPECT_EQ(capture_time_ms, time);
std::unique_ptr<RtpPacketToSend> packet_out =
hist_.GetPacketAndSetSendTime(kSeqNum, kMinRetransmitIntervalMs, true);
EXPECT_TRUE(packet_out);
EXPECT_EQ(len, packet_out->size());
EXPECT_EQ(capture_time_ms, packet_out->capture_time_ms());
fake_clock_.AdvanceTimeMilliseconds(kMinRetransmitIntervalMs - 1);
// Time has not elapsed. Packet should be found, but no bytes copied.
len = kMaxPacketLength;
EXPECT_FALSE(hist_->GetPacketAndSetSendTime(kSeqNum, kMinRetransmitIntervalMs,
true, packet_, &len, &time));
EXPECT_TRUE(hist_.HasRtpPacket(kSeqNum));
EXPECT_FALSE(
hist_.GetPacketAndSetSendTime(kSeqNum, kMinRetransmitIntervalMs, true));
}
TEST_F(RtpPacketHistoryTest, EarlyFirstResend) {
static const int64_t kMinRetransmitIntervalMs = 100;
hist_->SetStorePacketsStatus(true, 10);
size_t len = 0;
hist_.SetStorePacketsStatus(true, 10);
int64_t capture_time_ms = fake_clock_.TimeInMilliseconds();
CreateRtpPacket(kSeqNum, kSsrc, kPayload, kTimestamp, packet_, &len);
EXPECT_EQ(0, hist_->PutRTPPacket(packet_, len, capture_time_ms,
kAllowRetransmission));
std::unique_ptr<RtpPacketToSend> packet = CreateRtpPacket(kSeqNum);
rtc::CopyOnWriteBuffer buffer = packet->Buffer();
hist_.PutRtpPacket(std::move(packet), kAllowRetransmission, false);
// First transmission: TimeToSendPacket() call from pacer.
int64_t time;
len = kMaxPacketLength;
EXPECT_TRUE(
hist_->GetPacketAndSetSendTime(kSeqNum, 0, false, packet_, &len, &time));
EXPECT_TRUE(hist_.GetPacketAndSetSendTime(kSeqNum, 0, false));
fake_clock_.AdvanceTimeMilliseconds(kMinRetransmitIntervalMs - 1);
// Time has not elapsed, but this is the first retransmission request so
// allow anyway.
len = kMaxPacketLength;
EXPECT_TRUE(hist_->GetPacketAndSetSendTime(kSeqNum, kMinRetransmitIntervalMs,
true, packet_, &len, &time));
EXPECT_GT(len, 0u);
EXPECT_EQ(capture_time_ms, time);
std::unique_ptr<RtpPacketToSend> packet_out =
hist_.GetPacketAndSetSendTime(kSeqNum, kMinRetransmitIntervalMs, true);
EXPECT_TRUE(packet_out);
EXPECT_EQ(buffer, packet_out->Buffer());
EXPECT_EQ(capture_time_ms, packet_out->capture_time_ms());
fake_clock_.AdvanceTimeMilliseconds(kMinRetransmitIntervalMs - 1);
// Time has not elapsed. Packet should be found, but no bytes copied.
len = kMaxPacketLength;
EXPECT_FALSE(hist_->GetPacketAndSetSendTime(kSeqNum, kMinRetransmitIntervalMs,
true, packet_, &len, &time));
EXPECT_TRUE(hist_.HasRtpPacket(kSeqNum));
EXPECT_FALSE(
hist_.GetPacketAndSetSendTime(kSeqNum, kMinRetransmitIntervalMs, true));
}
TEST_F(RtpPacketHistoryTest, DynamicExpansion) {
hist_->SetStorePacketsStatus(true, 10);
size_t len;
int64_t capture_time_ms = fake_clock_.TimeInMilliseconds();
int64_t time;
hist_.SetStorePacketsStatus(true, 10);
// Add 4 packets, and then send them.
for (int i = 0; i < 4; ++i) {
len = 0;
CreateRtpPacket(kSeqNum + i, kSsrc, kPayload, kTimestamp, packet_, &len);
EXPECT_EQ(0, hist_->PutRTPPacket(packet_, len, capture_time_ms,
kAllowRetransmission));
std::unique_ptr<RtpPacketToSend> packet = CreateRtpPacket(kSeqNum + i);
hist_.PutRtpPacket(std::move(packet), kAllowRetransmission, false);
}
for (int i = 0; i < 4; ++i) {
len = kMaxPacketLength;
EXPECT_TRUE(hist_->GetPacketAndSetSendTime(kSeqNum + i, 100, false, packet_,
&len, &time));
EXPECT_TRUE(hist_.GetPacketAndSetSendTime(kSeqNum + i, 100, false));
}
capture_time_ms += 33;
fake_clock_.AdvanceTimeMilliseconds(33);
// Add 16 packets, and then send them. History should expand to make this
// work.
for (int i = 4; i < 20; ++i) {
len = 0;
CreateRtpPacket(kSeqNum + i, kSsrc, kPayload, kTimestamp, packet_, &len);
EXPECT_EQ(0, hist_->PutRTPPacket(packet_, len, capture_time_ms,
kAllowRetransmission));
std::unique_ptr<RtpPacketToSend> packet = CreateRtpPacket(kSeqNum + i);
hist_.PutRtpPacket(std::move(packet), kAllowRetransmission, false);
}
for (int i = 4; i < 20; ++i) {
len = kMaxPacketLength;
EXPECT_TRUE(hist_->GetPacketAndSetSendTime(kSeqNum + i, 100, false, packet_,
&len, &time));
EXPECT_TRUE(hist_.GetPacketAndSetSendTime(kSeqNum + i, 100, false));
}
fake_clock_.AdvanceTimeMilliseconds(100);
// Retransmit last 16 packets.
for (int i = 4; i < 20; ++i) {
len = kMaxPacketLength;
EXPECT_TRUE(hist_->GetPacketAndSetSendTime(kSeqNum + i, 100, false, packet_,
&len, &time));
EXPECT_TRUE(hist_.GetPacketAndSetSendTime(kSeqNum + i, 100, false));
}
}
TEST_F(RtpPacketHistoryTest, FullExpansion) {
static const int kSendSidePacketHistorySize = 600;
hist_->SetStorePacketsStatus(true, kSendSidePacketHistorySize);
size_t len;
int64_t capture_time_ms = fake_clock_.TimeInMilliseconds();
int64_t time;
for (size_t i = 0; i < kMaxHistoryCapacity + 1; ++i) {
len = 0;
CreateRtpPacket(kSeqNum + i, kSsrc, kPayload, kTimestamp, packet_, &len);
EXPECT_EQ(0, hist_->PutRTPPacket(packet_, len, capture_time_ms,
kAllowRetransmission));
hist_.SetStorePacketsStatus(true, kSendSidePacketHistorySize);
for (size_t i = 0; i < RtpPacketHistory::kMaxCapacity + 1; ++i) {
std::unique_ptr<RtpPacketToSend> packet = CreateRtpPacket(kSeqNum + i);
hist_.PutRtpPacket(std::move(packet), kAllowRetransmission, false);
}
fake_clock_.AdvanceTimeMilliseconds(100);
// Retransmit all packets currently in buffer.
for (size_t i = 1; i < kMaxHistoryCapacity + 1; ++i) {
len = kMaxPacketLength;
EXPECT_TRUE(hist_->GetPacketAndSetSendTime(kSeqNum + i, 100, false, packet_,
&len, &time));
for (size_t i = 1; i < RtpPacketHistory::kMaxCapacity + 1; ++i) {
EXPECT_TRUE(hist_.GetPacketAndSetSendTime(kSeqNum + i, 100, false));
}
}

View File

@ -18,9 +18,11 @@ class RtpPacketToSend : public rtp::Packet {
public:
explicit RtpPacketToSend(const ExtensionManager* extensions)
: Packet(extensions) {}
RtpPacketToSend(const RtpPacketToSend& packet) = default;
RtpPacketToSend(const ExtensionManager* extensions, size_t capacity)
: Packet(extensions, capacity) {}
RtpPacketToSend& operator=(const RtpPacketToSend& packet) = default;
// 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; }

View File

@ -174,12 +174,12 @@ TEST(RtpPacketTest, ParseMinimum) {
}
TEST(RtpPacketTest, ParseBuffer) {
rtc::Buffer unparsed(kMinimumPacket);
rtc::CopyOnWriteBuffer 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(raw, packet.data()); // Expect packet take the buffer without copy.
EXPECT_EQ(kSeqNum, packet.SequenceNumber());
EXPECT_EQ(kTimestamp, packet.Timestamp());
EXPECT_EQ(kSsrc, packet.Ssrc());

View File

@ -10,7 +10,6 @@
#include "webrtc/modules/rtp_rtcp/source/rtp_sender.h"
#include <stdlib.h> // srand
#include <algorithm>
#include <utility>
@ -24,22 +23,22 @@
#include "webrtc/modules/rtp_rtcp/include/rtp_cvo.h"
#include "webrtc/modules/rtp_rtcp/source/byte_io.h"
#include "webrtc/modules/rtp_rtcp/source/playout_delay_oracle.h"
#include "webrtc/modules/rtp_rtcp/source/rtp_header_extensions.h"
#include "webrtc/modules/rtp_rtcp/source/rtp_packet_to_send.h"
#include "webrtc/modules/rtp_rtcp/source/rtp_sender_audio.h"
#include "webrtc/modules/rtp_rtcp/source/rtp_sender_video.h"
#include "webrtc/modules/rtp_rtcp/source/time_util.h"
namespace webrtc {
// Max in the RFC 3550 is 255 bytes, we limit it to be modulus 32 for SRTP.
static const size_t kMaxPaddingLength = 224;
static const int kSendSideDelayWindowMs = 1000;
static const uint32_t kAbsSendTimeFraction = 18;
static const int kBitrateStatisticsWindowMs = 1000;
namespace {
const size_t kRtpHeaderLength = 12;
const uint16_t kMaxInitRtpSeqNumber = 32767; // 2^15 -1.
// Max in the RFC 3550 is 255 bytes, we limit it to be modulus 32 for SRTP.
constexpr size_t kMaxPaddingLength = 224;
constexpr int kSendSideDelayWindowMs = 1000;
constexpr size_t kRtpHeaderLength = 12;
constexpr uint16_t kMaxInitRtpSeqNumber = 32767; // 2^15 -1.
constexpr uint32_t kTimestampTicksPerMs = 90;
constexpr int kBitrateStatisticsWindowMs = 1000;
const char* FrameTypeToString(FrameType frame_type) {
switch (frame_type) {
@ -53,16 +52,13 @@ const char* FrameTypeToString(FrameType frame_type) {
return "";
}
// TODO(holmer): Merge this with the implementation in
// remote_bitrate_estimator_abs_send_time.cc.
uint32_t ConvertMsTo24Bits(int64_t time_ms) {
uint32_t time_24_bits =
static_cast<uint32_t>(
((static_cast<uint64_t>(time_ms) << kAbsSendTimeFraction) + 500) /
1000) &
0x00FFFFFF;
return time_24_bits;
void CountPacket(RtpPacketCounter* counter, const RtpPacketToSend& packet) {
++counter->packets;
counter->header_bytes += packet.headers_size();
counter->padding_bytes += packet.padding_size();
counter->payload_bytes += packet.payload_size();
}
} // namespace
RTPSender::RTPSender(
@ -127,10 +123,6 @@ RTPSender::RTPSender(
csrcs_(),
rtx_(kRtxOff),
retransmission_rate_limiter_(retransmission_rate_limiter) {
// We need to seed the random generator for BuildPaddingPacket() below.
// TODO(holmer,tommi): Note that TimeInMilliseconds might return 0 on Mac
// early on in the process.
srand(static_cast<uint32_t>(clock_->TimeInMilliseconds()));
ssrc_ = ssrc_db_->CreateSSRC();
RTC_DCHECK(ssrc_ != 0);
ssrc_rtx_ = ssrc_db_->CreateSSRC();
@ -346,17 +338,12 @@ void RTPSender::SetMaxPayloadLength(size_t max_payload_length) {
}
size_t RTPSender::MaxDataPayloadLength() const {
int rtx;
{
rtc::CritScope lock(&send_critsect_);
rtx = rtx_;
}
if (audio_configured_) {
return max_payload_length_ - RtpHeaderLength();
} else {
return max_payload_length_ - RtpHeaderLength() // RTP overhead.
- video_->FECPacketOverhead() // FEC/ULP/RED overhead.
- ((rtx) ? 2 : 0); // RTX overhead.
- (RtxStatus() ? kRtxHeaderSize : 0); // RTX overhead.
}
}
@ -543,41 +530,20 @@ size_t RTPSender::TrySendRedundantPayloads(size_t bytes_to_send,
return 0;
}
uint8_t buffer[IP_PACKET_SIZE];
int bytes_left = static_cast<int>(bytes_to_send);
while (bytes_left > 0) {
size_t length = bytes_left;
int64_t capture_time_ms;
if (!packet_history_.GetBestFittingPacket(buffer, &length,
&capture_time_ms)) {
std::unique_ptr<RtpPacketToSend> packet =
packet_history_.GetBestFittingPacket(bytes_left);
if (!packet)
break;
}
if (!PrepareAndSendPacket(buffer, length, capture_time_ms, true, false,
probe_cluster_id))
size_t payload_size = packet->payload_size();
if (!PrepareAndSendPacket(std::move(packet), true, false, probe_cluster_id))
break;
RtpUtility::RtpHeaderParser rtp_parser(buffer, length);
RTPHeader rtp_header;
rtp_parser.Parse(&rtp_header);
bytes_left -= static_cast<int>(length - rtp_header.headerLength);
bytes_left -= payload_size;
}
return bytes_to_send - bytes_left;
}
void RTPSender::BuildPaddingPacket(uint8_t* packet,
size_t header_length,
size_t padding_length) {
packet[0] |= 0x20; // Set padding bit.
int32_t* data = reinterpret_cast<int32_t*>(&(packet[header_length]));
// Fill data buffer with random data.
for (size_t j = 0; j < (padding_length >> 2); ++j) {
data[j] = rand(); // NOLINT
}
// Set number of padding bytes in the last byte of the packet.
packet[header_length + padding_length - 1] =
static_cast<uint8_t>(padding_length);
}
size_t RTPSender::SendPadData(size_t bytes,
bool timestamp_provided,
uint32_t timestamp,
@ -653,42 +619,36 @@ size_t RTPSender::SendPadData(size_t bytes,
}
}
uint8_t padding_packet[IP_PACKET_SIZE];
size_t header_length = 0;
{
rtc::CritScope lock(&send_critsect_);
header_length =
CreateRtpHeader(padding_packet, payload_type, ssrc, false, timestamp,
sequence_number, std::vector<uint32_t>());
}
BuildPaddingPacket(padding_packet, header_length, padding_bytes_in_packet);
size_t length = padding_bytes_in_packet + header_length;
RtpPacketToSend padding_packet(&rtp_header_extension_map_, IP_PACKET_SIZE);
padding_packet.SetPayloadType(payload_type);
padding_packet.SetMarker(false);
padding_packet.SetSequenceNumber(sequence_number);
padding_packet.SetTimestamp(timestamp);
padding_packet.SetSsrc(ssrc);
int64_t now_ms = clock_->TimeInMilliseconds();
RtpUtility::RtpHeaderParser rtp_parser(padding_packet, length);
RTPHeader rtp_header;
rtp_parser.Parse(&rtp_header);
if (capture_time_ms > 0) {
UpdateTransmissionTimeOffset(
padding_packet, length, rtp_header, now_ms - capture_time_ms);
padding_packet.SetExtension<TransmissionOffset>(
kTimestampTicksPerMs * (now_ms - capture_time_ms));
}
UpdateAbsoluteSendTime(padding_packet, length, rtp_header, now_ms);
padding_packet.SetExtension<AbsoluteSendTime>(now_ms);
PacketOptions options;
if (UpdateTransportSequenceNumber(padding_packet, length, rtp_header,
&options.packet_id)) {
if (transport_feedback_observer_)
transport_feedback_observer_->AddPacket(options.packet_id, length,
probe_cluster_id);
}
bool has_transport_seq_no =
UpdateTransportSequenceNumber(&padding_packet, &options.packet_id);
if (!SendPacketToNetwork(padding_packet, length, options))
padding_packet.SetPadding(padding_bytes_in_packet, &random_);
if (has_transport_seq_no && transport_feedback_observer_)
transport_feedback_observer_->AddPacket(
options.packet_id, padding_packet.size(), probe_cluster_id);
if (!SendPacketToNetwork(padding_packet, options))
break;
bytes_sent += padding_bytes_in_packet;
UpdateRtpStats(padding_packet, length, rtp_header, over_rtx, false);
UpdateRtpStats(padding_packet, over_rtx, false);
}
return bytes_sent;
@ -703,13 +663,9 @@ bool RTPSender::StorePackets() const {
}
int32_t RTPSender::ReSendPacket(uint16_t packet_id, int64_t min_resend_time) {
size_t length = IP_PACKET_SIZE;
uint8_t data_buffer[IP_PACKET_SIZE];
int64_t capture_time_ms;
if (!packet_history_.GetPacketAndSetSendTime(packet_id, min_resend_time, true,
data_buffer, &length,
&capture_time_ms)) {
std::unique_ptr<RtpPacketToSend> packet =
packet_history_.GetPacketAndSetSendTime(packet_id, min_resend_time, true);
if (!packet) {
// Packet not found.
return 0;
}
@ -717,53 +673,44 @@ int32_t RTPSender::ReSendPacket(uint16_t packet_id, int64_t min_resend_time) {
// Check if we're overusing retransmission bitrate.
// TODO(sprang): Add histograms for nack success or failure reasons.
RTC_DCHECK(retransmission_rate_limiter_);
if (!retransmission_rate_limiter_->TryUseRate(length))
if (!retransmission_rate_limiter_->TryUseRate(packet->size()))
return -1;
if (paced_sender_) {
RtpUtility::RtpHeaderParser rtp_parser(data_buffer, length);
RTPHeader header;
if (!rtp_parser.Parse(&header)) {
assert(false);
return -1;
}
// Convert from TickTime to Clock since capture_time_ms is based on
// TickTime.
int64_t corrected_capture_tims_ms = capture_time_ms + clock_delta_ms_;
paced_sender_->InsertPacket(
RtpPacketSender::kNormalPriority, header.ssrc, header.sequenceNumber,
corrected_capture_tims_ms, length - header.headerLength, true);
int64_t corrected_capture_tims_ms =
packet->capture_time_ms() + clock_delta_ms_;
paced_sender_->InsertPacket(RtpPacketSender::kNormalPriority,
packet->Ssrc(), packet->SequenceNumber(),
corrected_capture_tims_ms,
packet->payload_size(), true);
return length;
return packet->size();
}
int rtx = kRtxOff;
{
rtc::CritScope lock(&send_critsect_);
rtx = rtx_;
}
if (!PrepareAndSendPacket(data_buffer, length, capture_time_ms,
(rtx & kRtxRetransmitted) > 0, true,
PacketInfo::kNotAProbe)) {
bool rtx = (RtxStatus() & kRtxRetransmitted) > 0;
int32_t packet_size = static_cast<int32_t>(packet->size());
if (!PrepareAndSendPacket(std::move(packet), rtx, true,
PacketInfo::kNotAProbe))
return -1;
}
return static_cast<int32_t>(length);
return packet_size;
}
bool RTPSender::SendPacketToNetwork(const uint8_t* packet,
size_t size,
bool RTPSender::SendPacketToNetwork(const RtpPacketToSend& packet,
const PacketOptions& options) {
int bytes_sent = -1;
if (transport_) {
bytes_sent = transport_->SendRtp(packet, size, options)
? static_cast<int>(size)
bytes_sent = transport_->SendRtp(packet.data(), packet.size(), options)
? static_cast<int>(packet.size())
: -1;
if (event_log_ && bytes_sent > 0) {
event_log_->LogRtpHeader(kOutgoingPacket, MediaType::ANY, packet, size);
event_log_->LogRtpHeader(kOutgoingPacket, MediaType::ANY, packet.data(),
packet.size());
}
}
TRACE_EVENT_INSTANT2(TRACE_DISABLED_BY_DEFAULT("webrtc_rtp"),
"RTPSender::SendPacketToNetwork", "size", size, "sent",
bytes_sent);
"RTPSender::SendPacketToNetwork", "size", packet.size(),
"sent", bytes_sent);
// TODO(pwestin): Add a separate bitrate for sent bitrate after pacer.
if (bytes_sent <= 0) {
LOG(LS_WARNING) << "Transport failed to send packet";
@ -811,89 +758,75 @@ bool RTPSender::TimeToSendPacket(uint16_t sequence_number,
int64_t capture_time_ms,
bool retransmission,
int probe_cluster_id) {
size_t length = IP_PACKET_SIZE;
uint8_t data_buffer[IP_PACKET_SIZE];
int64_t stored_time_ms;
if (!packet_history_.GetPacketAndSetSendTime(sequence_number,
0,
retransmission,
data_buffer,
&length,
&stored_time_ms)) {
std::unique_ptr<RtpPacketToSend> packet =
packet_history_.GetPacketAndSetSendTime(sequence_number, 0,
retransmission);
if (!packet)
// Packet cannot be found. Allow sending to continue.
return true;
}
int rtx;
{
rtc::CritScope lock(&send_critsect_);
rtx = rtx_;
}
return PrepareAndSendPacket(data_buffer, length, capture_time_ms,
retransmission && (rtx & kRtxRetransmitted) > 0,
retransmission, probe_cluster_id);
return PrepareAndSendPacket(
std::move(packet),
retransmission && (RtxStatus() & kRtxRetransmitted) > 0, retransmission,
probe_cluster_id);
}
bool RTPSender::PrepareAndSendPacket(uint8_t* buffer,
size_t length,
int64_t capture_time_ms,
bool RTPSender::PrepareAndSendPacket(std::unique_ptr<RtpPacketToSend> packet,
bool send_over_rtx,
bool is_retransmit,
int probe_cluster_id) {
uint8_t* buffer_to_send_ptr = buffer;
RTC_DCHECK(packet);
int64_t capture_time_ms = packet->capture_time_ms();
RtpPacketToSend* packet_to_send = packet.get();
RtpUtility::RtpHeaderParser rtp_parser(buffer, length);
RTPHeader rtp_header;
rtp_parser.Parse(&rtp_header);
if (!is_retransmit && rtp_header.markerBit) {
if (!is_retransmit && packet->Marker()) {
TRACE_EVENT_ASYNC_END0(TRACE_DISABLED_BY_DEFAULT("webrtc_rtp"), "PacedSend",
capture_time_ms);
}
TRACE_EVENT_INSTANT2(
TRACE_DISABLED_BY_DEFAULT("webrtc_rtp"), "PrepareAndSendPacket",
"timestamp", rtp_header.timestamp, "seqnum", rtp_header.sequenceNumber);
TRACE_EVENT_INSTANT2(TRACE_DISABLED_BY_DEFAULT("webrtc_rtp"),
"PrepareAndSendPacket", "timestamp", packet->Timestamp(),
"seqnum", packet->SequenceNumber());
uint8_t data_buffer_rtx[IP_PACKET_SIZE];
std::unique_ptr<RtpPacketToSend> packet_rtx;
if (send_over_rtx) {
if (!BuildRtxPacket(buffer, &length, data_buffer_rtx))
packet_rtx = BuildRtxPacket(*packet);
if (!packet_rtx)
return false;
buffer_to_send_ptr = data_buffer_rtx;
packet_to_send = packet_rtx.get();
}
int64_t now_ms = clock_->TimeInMilliseconds();
int64_t diff_ms = now_ms - capture_time_ms;
UpdateTransmissionTimeOffset(buffer_to_send_ptr, length, rtp_header,
diff_ms);
UpdateAbsoluteSendTime(buffer_to_send_ptr, length, rtp_header, now_ms);
packet_to_send->SetExtension<TransmissionOffset>(kTimestampTicksPerMs *
diff_ms);
packet_to_send->SetExtension<AbsoluteSendTime>(now_ms);
PacketOptions options;
if (UpdateTransportSequenceNumber(buffer_to_send_ptr, length, rtp_header,
&options.packet_id)) {
if (transport_feedback_observer_)
transport_feedback_observer_->AddPacket(options.packet_id, length,
probe_cluster_id);
if (UpdateTransportSequenceNumber(packet_to_send, &options.packet_id) &&
transport_feedback_observer_) {
transport_feedback_observer_->AddPacket(
options.packet_id, packet_to_send->size(), probe_cluster_id);
}
if (!is_retransmit && !send_over_rtx) {
UpdateDelayStatistics(capture_time_ms, now_ms);
UpdateOnSendPacket(options.packet_id, capture_time_ms, rtp_header.ssrc);
UpdateDelayStatistics(packet->capture_time_ms(), now_ms);
UpdateOnSendPacket(options.packet_id, packet->capture_time_ms(),
packet->Ssrc());
}
bool ret = SendPacketToNetwork(buffer_to_send_ptr, length, options);
if (ret) {
if (!SendPacketToNetwork(*packet_to_send, options))
return false;
{
rtc::CritScope lock(&send_critsect_);
media_has_been_sent_ = true;
}
UpdateRtpStats(buffer_to_send_ptr, length, rtp_header, send_over_rtx,
is_retransmit);
return ret;
UpdateRtpStats(*packet_to_send, send_over_rtx, is_retransmit);
return true;
}
void RTPSender::UpdateRtpStats(const uint8_t* buffer,
size_t packet_length,
const RTPHeader& header,
void RTPSender::UpdateRtpStats(const RtpPacketToSend& packet,
bool is_rtx,
bool is_retransmit) {
StreamDataCounters* counters;
@ -908,27 +841,26 @@ void RTPSender::UpdateRtpStats(const uint8_t* buffer,
counters = &rtp_stats_;
}
total_bitrate_sent_.Update(packet_length, now_ms);
total_bitrate_sent_.Update(packet.size(), now_ms);
if (counters->first_packet_time_ms == -1)
if (counters->first_packet_time_ms == -1) {
counters->first_packet_time_ms = clock_->TimeInMilliseconds();
if (IsFecPacket(buffer, header))
counters->fec.AddPacket(packet_length, header);
if (is_retransmit) {
counters->retransmitted.AddPacket(packet_length, header);
nack_bitrate_sent_.Update(packet_length, now_ms);
}
if (IsFecPacket(packet)) {
CountPacket(&counters->fec, packet);
}
if (is_retransmit) {
CountPacket(&counters->retransmitted, packet);
nack_bitrate_sent_.Update(packet.size(), now_ms);
}
CountPacket(&counters->transmitted, packet);
counters->transmitted.AddPacket(packet_length, header);
if (rtp_stats_callback_)
if (rtp_stats_callback_) {
rtp_stats_callback_->DataCountersUpdated(*counters, ssrc);
}
}
bool RTPSender::IsFecPacket(const uint8_t* buffer,
const RTPHeader& header) const {
bool RTPSender::IsFecPacket(const RtpPacketToSend& packet) const {
if (!video_) {
return false;
}
@ -936,9 +868,8 @@ bool RTPSender::IsFecPacket(const uint8_t* buffer,
uint8_t pt_red;
uint8_t pt_fec;
video_->GenericFECStatus(&fec_enabled, &pt_red, &pt_fec);
return fec_enabled &&
header.payloadType == pt_red &&
buffer[header.headerLength] == pt_fec;
return fec_enabled && packet.PayloadType() == pt_red &&
packet.payload()[0] == pt_fec;
}
size_t RTPSender::TimeToSendPadding(size_t bytes, int probe_cluster_id) {
@ -951,7 +882,6 @@ size_t RTPSender::TimeToSendPadding(size_t bytes, int probe_cluster_id) {
return bytes_sent;
}
// TODO(pwestin): send in the RtpHeaderParser to avoid parsing it again.
bool RTPSender::SendToNetwork(uint8_t* buffer,
size_t payload_length,
size_t rtp_header_length,
@ -959,35 +889,38 @@ bool RTPSender::SendToNetwork(uint8_t* buffer,
StorageType storage,
RtpPacketSender::Priority priority) {
size_t length = payload_length + rtp_header_length;
RtpUtility::RtpHeaderParser rtp_parser(buffer, length);
RTPHeader rtp_header;
rtp_parser.Parse(&rtp_header);
std::unique_ptr<RtpPacketToSend> packet(
new RtpPacketToSend(&rtp_header_extension_map_, length));
RTC_CHECK(packet->Parse(buffer, length));
packet->set_capture_time_ms(capture_time_ms);
return SendToNetwork(std::move(packet), storage, priority);
}
bool RTPSender::SendToNetwork(std::unique_ptr<RtpPacketToSend> packet,
StorageType storage,
RtpPacketSender::Priority priority) {
RTC_DCHECK(packet);
int64_t now_ms = clock_->TimeInMilliseconds();
// |capture_time_ms| <= 0 is considered invalid.
// TODO(holmer): This should be changed all over Video Engine so that negative
// time is consider invalid, while 0 is considered a valid time.
if (capture_time_ms > 0) {
UpdateTransmissionTimeOffset(buffer, length, rtp_header,
now_ms - capture_time_ms);
}
UpdateAbsoluteSendTime(buffer, length, rtp_header, now_ms);
// Used for NACK and to spread out the transmission of packets.
if (packet_history_.PutRTPPacket(buffer, length, capture_time_ms, storage) !=
0) {
return false;
if (packet->capture_time_ms() > 0) {
packet->SetExtension<TransmissionOffset>(
kTimestampTicksPerMs * (now_ms - packet->capture_time_ms()));
}
packet->SetExtension<AbsoluteSendTime>(now_ms);
if (paced_sender_) {
uint16_t seq_no = packet->SequenceNumber();
uint32_t ssrc = packet->Ssrc();
// Correct offset between implementations of millisecond time stamps in
// TickTime and Clock.
int64_t corrected_time_ms = capture_time_ms + clock_delta_ms_;
paced_sender_->InsertPacket(priority, rtp_header.ssrc,
rtp_header.sequenceNumber, corrected_time_ms,
int64_t corrected_time_ms = packet->capture_time_ms() + clock_delta_ms_;
size_t payload_length = packet->payload_size();
packet_history_.PutRtpPacket(std::move(packet), storage, false);
paced_sender_->InsertPacket(priority, ssrc, seq_no, corrected_time_ms,
payload_length, false);
if (last_capture_time_ms_sent_ == 0 ||
corrected_time_ms > last_capture_time_ms_sent_) {
@ -1000,31 +933,32 @@ bool RTPSender::SendToNetwork(uint8_t* buffer,
}
PacketOptions options;
if (UpdateTransportSequenceNumber(buffer, length, rtp_header,
&options.packet_id)) {
if (transport_feedback_observer_)
transport_feedback_observer_->AddPacket(options.packet_id, length,
PacketInfo::kNotAProbe);
if (UpdateTransportSequenceNumber(packet.get(), &options.packet_id) &&
transport_feedback_observer_) {
transport_feedback_observer_->AddPacket(options.packet_id, packet->size(),
PacketInfo::kNotAProbe);
}
UpdateDelayStatistics(capture_time_ms, now_ms);
UpdateOnSendPacket(options.packet_id, capture_time_ms, rtp_header.ssrc);
bool sent = SendPacketToNetwork(buffer, length, options);
UpdateDelayStatistics(packet->capture_time_ms(), now_ms);
UpdateOnSendPacket(options.packet_id, packet->capture_time_ms(),
packet->Ssrc());
bool sent = SendPacketToNetwork(*packet, options);
if (sent) {
{
rtc::CritScope lock(&send_critsect_);
media_has_been_sent_ = true;
}
UpdateRtpStats(*packet, false, false);
}
// Mark the packet as sent in the history even if send failed. Dropping a
// packet here should be treated as any other packet drop so we should be
// ready for a retransmission.
packet_history_.SetSent(rtp_header.sequenceNumber);
packet_history_.PutRtpPacket(std::move(packet), storage, true);
if (!sent)
return false;
{
rtc::CritScope lock(&send_critsect_);
media_has_been_sent_ = true;
}
UpdateRtpStats(buffer, length, rtp_header, false, false);
return true;
return sent;
}
void RTPSender::UpdateDelayStatistics(int64_t capture_time_ms, int64_t now_ms) {
@ -1494,31 +1428,6 @@ RTPSender::ExtensionStatus RTPSender::VerifyExtension(
return ExtensionStatus::kOk;
}
void RTPSender::UpdateTransmissionTimeOffset(uint8_t* rtp_packet,
size_t rtp_packet_length,
const RTPHeader& rtp_header,
int64_t time_diff_ms) const {
size_t offset;
rtc::CritScope lock(&send_critsect_);
switch (VerifyExtension(kRtpExtensionTransmissionTimeOffset, rtp_packet,
rtp_packet_length, rtp_header,
kTransmissionTimeOffsetLength, &offset)) {
case ExtensionStatus::kNotRegistered:
return;
case ExtensionStatus::kError:
LOG(LS_WARNING) << "Failed to update transmission time offset.";
return;
case ExtensionStatus::kOk:
break;
default:
RTC_NOTREACHED();
}
// Update transmission offset field (converting to a 90 kHz timestamp).
ByteWriter<int32_t, 3>::WriteBigEndian(rtp_packet + offset + 1,
time_diff_ms * 90); // RTP timestamp.
}
bool RTPSender::UpdateAudioLevel(uint8_t* rtp_packet,
size_t rtp_packet_length,
const RTPHeader& rtp_header,
@ -1570,67 +1479,22 @@ bool RTPSender::UpdateVideoRotation(uint8_t* rtp_packet,
return true;
}
void RTPSender::UpdateAbsoluteSendTime(uint8_t* rtp_packet,
size_t rtp_packet_length,
const RTPHeader& rtp_header,
int64_t now_ms) const {
size_t offset;
bool RTPSender::UpdateTransportSequenceNumber(RtpPacketToSend* packet,
int* packet_id) const {
RTC_DCHECK(packet);
RTC_DCHECK(packet_id);
rtc::CritScope lock(&send_critsect_);
switch (VerifyExtension(kRtpExtensionAbsoluteSendTime, rtp_packet,
rtp_packet_length, rtp_header,
kAbsoluteSendTimeLength, &offset)) {
case ExtensionStatus::kNotRegistered:
return;
case ExtensionStatus::kError:
LOG(LS_WARNING) << "Failed to update absolute send time";
return;
case ExtensionStatus::kOk:
break;
default:
RTC_NOTREACHED();
}
// Update absolute send time field (convert ms to 24-bit unsigned with 18 bit
// fractional part).
ByteWriter<uint32_t, 3>::WriteBigEndian(rtp_packet + offset + 1,
ConvertMsTo24Bits(now_ms));
}
bool RTPSender::UpdateTransportSequenceNumber(uint8_t* rtp_packet,
size_t rtp_packet_length,
const RTPHeader& rtp_header,
int* sequence_number) const {
RTC_DCHECK(sequence_number);
size_t offset;
rtc::CritScope lock(&send_critsect_);
switch (VerifyExtension(kRtpExtensionTransportSequenceNumber, rtp_packet,
rtp_packet_length, rtp_header,
kTransportSequenceNumberLength, &offset)) {
case ExtensionStatus::kNotRegistered:
return false;
case ExtensionStatus::kError:
LOG(LS_WARNING) << "Failed to update transport sequence number";
return false;
case ExtensionStatus::kOk:
break;
default:
RTC_NOTREACHED();
}
if (!AllocateTransportSequenceNumber(sequence_number))
if (!rtp_header_extension_map_.IsRegistered(TransportSequenceNumber::kId))
return false;
BuildTransportSequenceNumberExtension(rtp_packet + offset, *sequence_number);
return true;
}
bool RTPSender::AllocateTransportSequenceNumber(int* packet_id) const {
if (!transport_sequence_number_allocator_)
return false;
*packet_id = transport_sequence_number_allocator_->AllocateSequenceNumber();
if (!packet->SetExtension<TransportSequenceNumber>(*packet_id))
return false;
return true;
}
@ -1803,53 +1667,46 @@ int32_t RTPSender::SetFecParameters(
return 0;
}
bool RTPSender::BuildRtxPacket(uint8_t* buffer,
size_t* length,
uint8_t* buffer_rtx) {
rtc::CritScope lock(&send_critsect_);
if (!sending_media_)
return false;
uint8_t* data_buffer_rtx = buffer_rtx;
// Add RTX header.
RtpUtility::RtpHeaderParser rtp_parser(
reinterpret_cast<const uint8_t*>(buffer), *length);
RTPHeader rtp_header;
rtp_parser.Parse(&rtp_header);
std::unique_ptr<RtpPacketToSend> RTPSender::BuildRtxPacket(
const RtpPacketToSend& packet) {
// TODO(danilchap): Create rtx packet with extra capacity for SRTP
// when transport interface would be updated to take buffer class.
std::unique_ptr<RtpPacketToSend> rtx_packet(new RtpPacketToSend(
&rtp_header_extension_map_, packet.size() + kRtxHeaderSize));
// Add original RTP header.
memcpy(data_buffer_rtx, buffer, rtp_header.headerLength);
rtx_packet->CopyHeaderFrom(packet);
{
rtc::CritScope lock(&send_critsect_);
if (!sending_media_)
return nullptr;
// Replace payload type, if a specific type is set for RTX.
auto kv = rtx_payload_type_map_.find(packet.PayloadType());
// Replace payload type, if a specific type is set for RTX.
auto kv = rtx_payload_type_map_.find(rtp_header.payloadType);
// Use rtx mapping associated with media codec if we can't find one, assuming
// it's red.
// TODO(holmer): Remove once old Chrome versions don't rely on this.
if (kv == rtx_payload_type_map_.end())
kv = rtx_payload_type_map_.find(payload_type_);
if (kv != rtx_payload_type_map_.end())
data_buffer_rtx[1] = kv->second;
if (rtp_header.markerBit)
data_buffer_rtx[1] |= kRtpMarkerBitMask;
// Use rtx mapping associated with media codec if we can't find one,
// assume it's red.
// TODO(holmer): Remove once old Chrome versions don't rely on this.
if (kv == rtx_payload_type_map_.end())
kv = rtx_payload_type_map_.find(payload_type_);
if (kv != rtx_payload_type_map_.end())
rtx_packet->SetPayloadType(kv->second);
// Replace sequence number.
uint8_t* ptr = data_buffer_rtx + 2;
ByteWriter<uint16_t>::WriteBigEndian(ptr, sequence_number_rtx_++);
// Replace sequence number.
rtx_packet->SetSequenceNumber(sequence_number_rtx_++);
// Replace SSRC.
ptr += 6;
ByteWriter<uint32_t>::WriteBigEndian(ptr, ssrc_rtx_);
// Replace SSRC.
rtx_packet->SetSsrc(ssrc_rtx_);
}
uint8_t* rtx_payload =
rtx_packet->AllocatePayload(packet.payload_size() + kRtxHeaderSize);
RTC_DCHECK(rtx_payload);
// Add OSN (original sequence number).
ptr = data_buffer_rtx + rtp_header.headerLength;
ByteWriter<uint16_t>::WriteBigEndian(ptr, rtp_header.sequenceNumber);
ptr += 2;
ByteWriter<uint16_t>::WriteBigEndian(rtx_payload, packet.SequenceNumber());
// Add original payload data.
memcpy(ptr, buffer + rtp_header.headerLength,
*length - rtp_header.headerLength);
*length += 2;
return true;
memcpy(rtx_payload + kRtxHeaderSize, packet.payload(), packet.payload_size());
return rtx_packet;
}
void RTPSender::RegisterRtpStatisticsCallback(

View File

@ -35,9 +35,10 @@
namespace webrtc {
class RateLimiter;
class RtcEventLog;
class RtpPacketToSend;
class RTPSenderAudio;
class RTPSenderVideo;
class RtcEventLog;
class RTPSenderInterface {
public:
@ -277,12 +278,16 @@ class RTPSender : public RTPSenderInterface {
uint32_t Timestamp() const override;
uint32_t SSRC() const override;
// Deprecated. Create RtpPacketToSend instead and use next function.
bool SendToNetwork(uint8_t* data_buffer,
size_t payload_length,
size_t rtp_header_length,
int64_t capture_time_ms,
StorageType storage,
RtpPacketSender::Priority priority) override;
bool SendToNetwork(std::unique_ptr<RtpPacketToSend> packet,
StorageType storage,
RtpPacketSender::Priority priority);
// Audio.
@ -359,9 +364,7 @@ class RTPSender : public RTPSenderInterface {
const std::vector<uint32_t>& csrcs) const
EXCLUSIVE_LOCKS_REQUIRED(send_critsect_);
bool PrepareAndSendPacket(uint8_t* buffer,
size_t length,
int64_t capture_time_ms,
bool PrepareAndSendPacket(std::unique_ptr<RtpPacketToSend> packet,
bool send_over_rtx,
bool is_retransmit,
int probe_cluster_id);
@ -370,14 +373,10 @@ class RTPSender : public RTPSenderInterface {
// return a larger value that their argument.
size_t TrySendRedundantPayloads(size_t bytes, int probe_cluster_id);
void BuildPaddingPacket(uint8_t* packet,
size_t header_length,
size_t padding_length);
std::unique_ptr<RtpPacketToSend> BuildRtxPacket(
const RtpPacketToSend& packet);
bool BuildRtxPacket(uint8_t* buffer, size_t* length, uint8_t* buffer_rtx);
bool SendPacketToNetwork(const uint8_t* packet,
size_t size,
bool SendPacketToNetwork(const RtpPacketToSend& packet,
const PacketOptions& options);
void UpdateDelayStatistics(int64_t capture_time_ms, int64_t now_ms);
@ -394,19 +393,8 @@ class RTPSender : public RTPSenderInterface {
size_t* position) const
EXCLUSIVE_LOCKS_REQUIRED(send_critsect_);
void UpdateTransmissionTimeOffset(uint8_t* rtp_packet,
size_t rtp_packet_length,
const RTPHeader& rtp_header,
int64_t time_diff_ms) const;
void UpdateAbsoluteSendTime(uint8_t* rtp_packet,
size_t rtp_packet_length,
const RTPHeader& rtp_header,
int64_t now_ms) const;
bool UpdateTransportSequenceNumber(uint8_t* rtp_packet,
size_t rtp_packet_length,
const RTPHeader& rtp_header,
int* sequence_number) const;
bool UpdateTransportSequenceNumber(RtpPacketToSend* packet,
int* packet_id) const;
void UpdatePlayoutDelayLimits(uint8_t* rtp_packet,
size_t rtp_packet_length,
@ -414,14 +402,10 @@ class RTPSender : public RTPSenderInterface {
uint16_t min_playout_delay,
uint16_t max_playout_delay) const;
bool AllocateTransportSequenceNumber(int* packet_id) const;
void UpdateRtpStats(const uint8_t* buffer,
size_t packet_length,
const RTPHeader& header,
void UpdateRtpStats(const RtpPacketToSend& packet,
bool is_rtx,
bool is_retransmit);
bool IsFecPacket(const uint8_t* buffer, const RTPHeader& header) const;
bool IsFecPacket(const RtpPacketToSend& packet) const;
Clock* const clock_;
const int64_t clock_delta_ms_;
@ -458,7 +442,7 @@ class RTPSender : public RTPSenderInterface {
PlayoutDelayOracle playout_delay_oracle_;
bool playout_delay_active_ GUARDED_BY(send_critsect_);
RTPPacketHistory packet_history_;
RtpPacketHistory packet_history_;
// Statistics
rtc::CriticalSection statistics_crit_;

View File

@ -149,6 +149,7 @@ class RtpSenderTest : public ::testing::Test {
&mock_rtc_event_log_, &send_packet_observer_,
&retransmission_rate_limiter_));
rtp_sender_->SetSequenceNumber(kSeqNum);
rtp_sender_->SetSendPayloadType(kPayload);
}
SimulatedClock fake_clock_;