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:
parent
6b42cef98d
commit
31e4e806b1
@ -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;
|
||||
}
|
||||
|
||||
|
||||
@ -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 {
|
||||
|
||||
@ -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;
|
||||
}
|
||||
|
||||
|
||||
@ -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>
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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_
|
||||
|
||||
@ -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));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -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; }
|
||||
|
||||
@ -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());
|
||||
|
||||
@ -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(
|
||||
|
||||
@ -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_;
|
||||
|
||||
@ -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_;
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user