Split RTPSender into pre- and post-pacer parts.
Post-pacer code now contained in RtpSenderEgress class.
For now, this is a member of RTPSender. More refactoring is needed to
make clean split.
Bug: webrtc:11036
Change-Id: I95264d013de120601784f130ba81c7b234446980
Reviewed-on: https://webrtc-review.googlesource.com/c/src/+/157172
Reviewed-by: Danil Chapovalov <danilchap@webrtc.org>
Commit-Queue: Erik Språng <sprang@webrtc.org>
Cr-Commit-Position: refs/heads/master@{#29519}
diff --git a/modules/rtp_rtcp/BUILD.gn b/modules/rtp_rtcp/BUILD.gn
index 3d7eeab..f421100 100644
--- a/modules/rtp_rtcp/BUILD.gn
+++ b/modules/rtp_rtcp/BUILD.gn
@@ -185,6 +185,8 @@
"source/rtp_sender.h",
"source/rtp_sender_audio.cc",
"source/rtp_sender_audio.h",
+ "source/rtp_sender_egress.cc",
+ "source/rtp_sender_egress.h",
"source/rtp_sender_video.cc",
"source/rtp_sender_video.h",
"source/rtp_sequence_number_map.cc",
@@ -232,6 +234,7 @@
"../../api/transport:field_trial_based_config",
"../../api/transport:webrtc_key_value_config",
"../../api/transport/rtp:rtp_source",
+ "../../api/units:data_rate",
"../../api/units:time_delta",
"../../api/units:timestamp",
"../../api/video:video_bitrate_allocation",
diff --git a/modules/rtp_rtcp/source/rtp_sender.cc b/modules/rtp_rtcp/source/rtp_sender.cc
index c9555fa..e2f57fe 100644
--- a/modules/rtp_rtcp/source/rtp_sender.cc
+++ b/modules/rtp_rtcp/source/rtp_sender.cc
@@ -19,7 +19,6 @@
#include "absl/strings/match.h"
#include "api/array_view.h"
#include "api/rtc_event_log/rtc_event_log.h"
-#include "api/transport/field_trial_based_config.h"
#include "logging/rtc_event_log/events/rtc_event_rtp_packet_outgoing.h"
#include "modules/rtp_rtcp/include/rtp_cvo.h"
#include "modules/rtp_rtcp/source/byte_io.h"
@@ -40,11 +39,9 @@
// Max in the RFC 3550 is 255 bytes, we limit it to be modulus 32 for SRTP.
constexpr size_t kMaxPaddingLength = 224;
constexpr size_t kMinAudioPaddingLength = 50;
-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;
// Min size needed to get payload padding from packet history.
constexpr int kMinPayloadPaddingBytes = 50;
@@ -87,13 +84,6 @@
RtpGenericFrameDescriptorExtension01::kMaxSizeBytes},
};
-bool IsEnabled(absl::string_view name,
- const WebRtcKeyValueConfig* field_trials) {
- FieldTrialBasedConfig default_trials;
- auto& trials = field_trials ? *field_trials : default_trials;
- return trials.Lookup(name).find("Enabled") == 0;
-}
-
bool HasBweExtension(const RtpHeaderExtensionMap& extensions_map) {
return extensions_map.IsRegistered(kRtpExtensionTransportSequenceNumber) ||
extensions_map.IsRegistered(kRtpExtensionTransportSequenceNumber02) ||
@@ -133,27 +123,11 @@
config.paced_sender ? nullptr : new NonPacedPacketSender(this)),
paced_sender_(config.paced_sender ? config.paced_sender
: non_paced_packet_sender_.get()),
- transport_feedback_observer_(config.transport_feedback_callback),
- transport_(config.outgoing_transport),
- sending_media_(true), // Default to sending media.
- force_part_of_allocation_(false),
+ sending_media_(true), // Default to sending media.
max_packet_size_(IP_PACKET_SIZE - 28), // Default is IP-v4/UDP.
last_payload_type_(-1),
rtp_header_extension_map_(config.extmap_allow_mixed),
packet_history_(clock_),
- // Statistics
- send_delays_(),
- max_delay_it_(send_delays_.end()),
- sum_delays_ms_(0),
- total_packet_send_delay_ms_(0),
- rtp_stats_callback_(config.rtp_stats_callback),
- total_bitrate_sent_(kBitrateStatisticsWindowMs,
- RateStatistics::kBpsScale),
- nack_bitrate_sent_(kBitrateStatisticsWindowMs, RateStatistics::kBpsScale),
- send_side_delay_observer_(config.send_side_delay_observer),
- event_log_(config.event_log),
- send_packet_observer_(config.send_packet_observer),
- bitrate_callback_(config.send_bitrate_observer),
// RTP variables
sequence_number_forced_(false),
ssrc_has_acked_(false),
@@ -161,17 +135,12 @@
last_rtp_timestamp_(0),
capture_time_ms_(0),
last_timestamp_time_ms_(0),
- media_has_been_sent_(false),
last_packet_marker_bit_(false),
csrcs_(),
rtx_(kRtxOff),
- rtp_overhead_bytes_per_packet_(0),
supports_bwe_extension_(false),
retransmission_rate_limiter_(config.retransmission_rate_limiter),
- overhead_observer_(config.overhead_observer),
- populate_network2_timestamp_(config.populate_network2_timestamp),
- send_side_bwe_with_overhead_(
- IsEnabled("WebRTC-SendSideBwe-WithOverhead", config.field_trials)) {
+ egress_(config, &packet_history_, clock_) {
// This random initialization is not intended to be cryptographic strong.
timestamp_offset_ = random_.Rand<uint32_t>();
// Random start, 16 bits. Can't be 0.
@@ -203,15 +172,11 @@
}
uint16_t RTPSender::ActualSendBitrateKbit() const {
- rtc::CritScope cs(&statistics_crit_);
- return static_cast<uint16_t>(
- total_bitrate_sent_.Rate(clock_->TimeInMilliseconds()).value_or(0) /
- 1000);
+ return egress_.SendBitrate().kbps<uint16_t>();
}
uint32_t RTPSender::NackOverheadRate() const {
- rtc::CritScope cs(&statistics_crit_);
- return nack_bitrate_sent_.Rate(clock_->TimeInMilliseconds()).value_or(0);
+ return egress_.NackOverheadRate().bps<uint32_t>();
}
void RTPSender::SetExtmapAllowMixed(bool extmap_allow_mixed) {
@@ -356,28 +321,6 @@
rtx_ssrc_has_acked_ = true;
}
-bool RTPSender::SendPacketToNetwork(const RtpPacketToSend& packet,
- const PacketOptions& options,
- const PacedPacketInfo& pacing_info) {
- int bytes_sent = -1;
- if (transport_) {
- UpdateRtpOverhead(packet);
- bytes_sent = transport_->SendRtp(packet.data(), packet.size(), options)
- ? static_cast<int>(packet.size())
- : -1;
- if (event_log_ && bytes_sent > 0) {
- event_log_->Log(std::make_unique<RtcEventRtpPacketOutgoing>(
- packet, pacing_info.probe_cluster_id));
- }
- }
- // TODO(pwestin): Add a separate bitrate for sent bitrate after pacer.
- if (bytes_sent <= 0) {
- RTC_LOG(LS_WARNING) << "Transport failed to send packet.";
- return false;
- }
- return true;
-}
-
void RTPSender::OnReceivedNack(
const std::vector<uint16_t>& nack_sequence_numbers,
int64_t avg_rtt) {
@@ -398,116 +341,14 @@
const PacedPacketInfo& pacing_info) {
RTC_DCHECK(packet);
- const uint32_t packet_ssrc = packet->Ssrc();
- const auto packet_type = packet->packet_type();
- RTC_DCHECK(packet_type.has_value());
-
- PacketOptions options;
- bool is_media = false;
- bool is_rtx = false;
{
rtc::CritScope lock(&send_critsect_);
if (!sending_media_) {
return false;
}
-
- switch (*packet_type) {
- case RtpPacketToSend::Type::kAudio:
- case RtpPacketToSend::Type::kVideo:
- if (packet_ssrc != ssrc_) {
- return false;
- }
- is_media = true;
- break;
- case RtpPacketToSend::Type::kRetransmission:
- case RtpPacketToSend::Type::kPadding:
- // Both padding and retransmission must be on either the media or the
- // RTX stream.
- if (packet_ssrc == rtx_ssrc_) {
- is_rtx = true;
- } else if (packet_ssrc != ssrc_) {
- return false;
- }
- break;
- case RtpPacketToSend::Type::kForwardErrorCorrection:
- // FlexFEC is on separate SSRC, ULPFEC uses media SSRC.
- if (packet_ssrc != ssrc_ && packet_ssrc != flexfec_ssrc_) {
- return false;
- }
- break;
- }
-
- options.included_in_allocation = force_part_of_allocation_;
}
- // Bug webrtc:7859. While FEC is invoked from rtp_sender_video, and not after
- // the pacer, these modifications of the header below are happening after the
- // FEC protection packets are calculated. This will corrupt recovered packets
- // at the same place. It's not an issue for extensions, which are present in
- // all the packets (their content just may be incorrect on recovered packets).
- // In case of VideoTimingExtension, since it's present not in every packet,
- // data after rtp header may be corrupted if these packets are protected by
- // the FEC.
- int64_t now_ms = clock_->TimeInMilliseconds();
- int64_t diff_ms = now_ms - packet->capture_time_ms();
- if (packet->IsExtensionReserved<TransmissionOffset>()) {
- packet->SetExtension<TransmissionOffset>(kTimestampTicksPerMs * diff_ms);
- }
- if (packet->IsExtensionReserved<AbsoluteSendTime>()) {
- packet->SetExtension<AbsoluteSendTime>(
- AbsoluteSendTime::MsTo24Bits(now_ms));
- }
-
- if (packet->HasExtension<VideoTimingExtension>()) {
- if (populate_network2_timestamp_) {
- packet->set_network2_time_ms(now_ms);
- } else {
- packet->set_pacer_exit_time_ms(now_ms);
- }
- }
-
- // Downstream code actually uses this flag to distinguish between media and
- // everything else.
- options.is_retransmit = !is_media;
- if (auto packet_id = packet->GetExtension<TransportSequenceNumber>()) {
- options.packet_id = *packet_id;
- options.included_in_feedback = true;
- options.included_in_allocation = true;
- AddPacketToTransportFeedback(*packet_id, *packet, pacing_info);
- }
-
- options.application_data.assign(packet->application_data().begin(),
- packet->application_data().end());
-
- if (packet->packet_type() != RtpPacketToSend::Type::kPadding &&
- packet->packet_type() != RtpPacketToSend::Type::kRetransmission) {
- UpdateDelayStatistics(packet->capture_time_ms(), now_ms, packet_ssrc);
- UpdateOnSendPacket(options.packet_id, packet->capture_time_ms(),
- packet_ssrc);
- }
-
- const bool send_success = SendPacketToNetwork(*packet, options, pacing_info);
-
- // Put packet in retransmission history or update pending status even if
- // actual sending fails.
- if (is_media && packet->allow_retransmission()) {
- packet_history_.PutRtpPacket(std::make_unique<RtpPacketToSend>(*packet),
- now_ms);
- } else if (packet->retransmitted_sequence_number()) {
- packet_history_.MarkPacketAsSent(*packet->retransmitted_sequence_number());
- }
-
- if (send_success) {
- UpdateRtpStats(*packet, is_rtx,
- packet_type == RtpPacketToSend::Type::kRetransmission);
-
- rtc::CritScope lock(&send_critsect_);
- media_has_been_sent_ = true;
- }
-
- // Return true even if transport failed (will be handled by retransmissions
- // instead in that case), so that PacketRouter does not have to iterate over
- // all other RTP modules and fail to send there too.
+ egress_.SendPacket(packet, pacing_info);
return true;
}
@@ -522,33 +363,6 @@
(rtx_ & kRtxRedundantPayloads);
}
-void RTPSender::UpdateRtpStats(const RtpPacketToSend& packet,
- bool is_rtx,
- bool is_retransmit) {
- int64_t now_ms = clock_->TimeInMilliseconds();
-
- rtc::CritScope lock(&statistics_crit_);
- StreamDataCounters* counters = is_rtx ? &rtx_rtp_stats_ : &rtp_stats_;
-
- total_bitrate_sent_.Update(packet.size(), now_ms);
-
- if (counters->first_packet_time_ms == -1)
- counters->first_packet_time_ms = now_ms;
-
- if (packet.packet_type() == RtpPacketToSend::Type::kForwardErrorCorrection) {
- counters->fec.AddPacket(packet);
- }
-
- if (is_retransmit) {
- counters->retransmitted.AddPacket(packet);
- nack_bitrate_sent_.Update(packet.size(), now_ms);
- }
- counters->transmitted.AddPacket(packet);
-
- if (rtp_stats_callback_)
- rtp_stats_callback_->DataCountersUpdated(*counters, packet.Ssrc());
-}
-
std::vector<std::unique_ptr<RtpPacketToSend>> RTPSender::GeneratePadding(
size_t target_size_bytes) {
// This method does not actually send packets, it just generates
@@ -622,7 +436,7 @@
// Without abs-send-time or transport sequence number a media packet
// must be sent before padding so that the timestamps used for
// estimation are correct.
- if (!media_has_been_sent_ &&
+ if (!egress_.MediaHasBeenSent() &&
!(rtp_header_extension_map_.IsRegistered(AbsoluteSendTime::kId) ||
rtp_header_extension_map_.IsRegistered(
TransportSequenceNumber::kId))) {
@@ -697,109 +511,8 @@
paced_sender_->EnqueuePackets(std::move(packets));
}
-void RTPSender::RecomputeMaxSendDelay() {
- max_delay_it_ = send_delays_.begin();
- for (auto it = send_delays_.begin(); it != send_delays_.end(); ++it) {
- if (it->second >= max_delay_it_->second) {
- max_delay_it_ = it;
- }
- }
-}
-
-void RTPSender::UpdateDelayStatistics(int64_t capture_time_ms,
- int64_t now_ms,
- uint32_t ssrc) {
- if (!send_side_delay_observer_ || capture_time_ms <= 0)
- return;
-
- int avg_delay_ms = 0;
- int max_delay_ms = 0;
- uint64_t total_packet_send_delay_ms = 0;
- {
- rtc::CritScope cs(&statistics_crit_);
- // Compute the max and average of the recent capture-to-send delays.
- // The time complexity of the current approach depends on the distribution
- // of the delay values. This could be done more efficiently.
-
- // Remove elements older than kSendSideDelayWindowMs.
- auto lower_bound =
- send_delays_.lower_bound(now_ms - kSendSideDelayWindowMs);
- for (auto it = send_delays_.begin(); it != lower_bound; ++it) {
- if (max_delay_it_ == it) {
- max_delay_it_ = send_delays_.end();
- }
- sum_delays_ms_ -= it->second;
- }
- send_delays_.erase(send_delays_.begin(), lower_bound);
- if (max_delay_it_ == send_delays_.end()) {
- // Removed the previous max. Need to recompute.
- RecomputeMaxSendDelay();
- }
-
- // Add the new element.
- RTC_DCHECK_GE(now_ms, static_cast<int64_t>(0));
- RTC_DCHECK_LE(now_ms, std::numeric_limits<int64_t>::max() / 2);
- RTC_DCHECK_GE(capture_time_ms, static_cast<int64_t>(0));
- RTC_DCHECK_LE(capture_time_ms, std::numeric_limits<int64_t>::max() / 2);
- int64_t diff_ms = now_ms - capture_time_ms;
- RTC_DCHECK_GE(diff_ms, static_cast<int64_t>(0));
- RTC_DCHECK_LE(diff_ms,
- static_cast<int64_t>(std::numeric_limits<int>::max()));
- int new_send_delay = rtc::dchecked_cast<int>(now_ms - capture_time_ms);
- SendDelayMap::iterator it;
- bool inserted;
- std::tie(it, inserted) =
- send_delays_.insert(std::make_pair(now_ms, new_send_delay));
- if (!inserted) {
- // TODO(terelius): If we have multiple delay measurements during the same
- // millisecond then we keep the most recent one. It is not clear that this
- // is the right decision, but it preserves an earlier behavior.
- int previous_send_delay = it->second;
- sum_delays_ms_ -= previous_send_delay;
- it->second = new_send_delay;
- if (max_delay_it_ == it && new_send_delay < previous_send_delay) {
- RecomputeMaxSendDelay();
- }
- }
- if (max_delay_it_ == send_delays_.end() ||
- it->second >= max_delay_it_->second) {
- max_delay_it_ = it;
- }
- sum_delays_ms_ += new_send_delay;
- total_packet_send_delay_ms_ += new_send_delay;
- total_packet_send_delay_ms = total_packet_send_delay_ms_;
-
- size_t num_delays = send_delays_.size();
- RTC_DCHECK(max_delay_it_ != send_delays_.end());
- max_delay_ms = rtc::dchecked_cast<int>(max_delay_it_->second);
- int64_t avg_ms = (sum_delays_ms_ + num_delays / 2) / num_delays;
- RTC_DCHECK_GE(avg_ms, static_cast<int64_t>(0));
- RTC_DCHECK_LE(avg_ms,
- static_cast<int64_t>(std::numeric_limits<int>::max()));
- avg_delay_ms =
- rtc::dchecked_cast<int>((sum_delays_ms_ + num_delays / 2) / num_delays);
- }
- send_side_delay_observer_->SendSideDelayUpdated(
- avg_delay_ms, max_delay_ms, total_packet_send_delay_ms, ssrc);
-}
-
-void RTPSender::UpdateOnSendPacket(int packet_id,
- int64_t capture_time_ms,
- uint32_t ssrc) {
- if (!send_packet_observer_ || capture_time_ms <= 0 || packet_id == -1)
- return;
-
- send_packet_observer_->OnSendPacket(packet_id, capture_time_ms, ssrc);
-}
-
void RTPSender::ProcessBitrate() {
- if (!bitrate_callback_)
- return;
- int64_t now_ms = clock_->TimeInMilliseconds();
-
- rtc::CritScope lock(&statistics_crit_);
- bitrate_callback_->Notify(total_bitrate_sent_.Rate(now_ms).value_or(0),
- nack_bitrate_sent_.Rate(now_ms).value_or(0), ssrc_);
+ egress_.ProcessBitrateAndNotifyObservers();
}
size_t RTPSender::RtpHeaderLength() const {
@@ -820,9 +533,7 @@
void RTPSender::GetDataCounters(StreamDataCounters* rtp_stats,
StreamDataCounters* rtx_stats) const {
- rtc::CritScope lock(&statistics_crit_);
- *rtp_stats = rtp_stats_;
- *rtx_stats = rtx_rtp_stats_;
+ egress_.GetDataCounters(rtp_stats, rtx_stats);
}
std::unique_ptr<RtpPacketToSend> RTPSender::AllocatePacket() const {
@@ -895,8 +606,7 @@
}
void RTPSender::SetAsPartOfAllocation(bool part_of_allocation) {
- rtc::CritScope lock(&send_critsect_);
- force_part_of_allocation_ = part_of_allocation;
+ egress_.ForceIncludeSendPacketsInAllocation(part_of_allocation);
}
void RTPSender::SetTimestampOffset(uint32_t timestamp) {
@@ -1072,8 +782,7 @@
}
uint32_t RTPSender::BitrateSent() const {
- rtc::CritScope cs(&statistics_crit_);
- return total_bitrate_sent_.Rate(clock_->TimeInMilliseconds()).value_or(0);
+ return egress_.SendBitrate().bps<uint32_t>();
}
void RTPSender::SetRtpState(const RtpState& rtp_state) {
@@ -1084,8 +793,8 @@
last_rtp_timestamp_ = rtp_state.timestamp;
capture_time_ms_ = rtp_state.capture_time_ms;
last_timestamp_time_ms_ = rtp_state.last_timestamp_time_ms;
- media_has_been_sent_ = rtp_state.media_has_been_sent;
ssrc_has_acked_ = rtp_state.ssrc_has_acked;
+ egress_.SetMediaHasBeenSent(rtp_state.media_has_been_sent);
}
RtpState RTPSender::GetRtpState() const {
@@ -1097,7 +806,7 @@
state.timestamp = last_rtp_timestamp_;
state.capture_time_ms = capture_time_ms_;
state.last_timestamp_time_ms = last_timestamp_time_ms_;
- state.media_has_been_sent = media_has_been_sent_;
+ state.media_has_been_sent = egress_.MediaHasBeenSent();
state.ssrc_has_acked = ssrc_has_acked_;
return state;
@@ -1120,42 +829,6 @@
return state;
}
-void RTPSender::AddPacketToTransportFeedback(
- uint16_t packet_id,
- const RtpPacketToSend& packet,
- const PacedPacketInfo& pacing_info) {
- if (transport_feedback_observer_) {
- size_t packet_size = packet.payload_size() + packet.padding_size();
- if (send_side_bwe_with_overhead_) {
- packet_size = packet.size();
- }
-
- RtpPacketSendInfo packet_info;
- packet_info.ssrc = SSRC();
- packet_info.transport_sequence_number = packet_id;
- packet_info.has_rtp_sequence_number = true;
- packet_info.rtp_sequence_number = packet.SequenceNumber();
- packet_info.length = packet_size;
- packet_info.pacing_info = pacing_info;
- transport_feedback_observer_->OnAddPacket(packet_info);
- }
-}
-
-void RTPSender::UpdateRtpOverhead(const RtpPacketToSend& packet) {
- if (!overhead_observer_)
- return;
- size_t overhead_bytes_per_packet;
- {
- rtc::CritScope lock(&send_critsect_);
- if (rtp_overhead_bytes_per_packet_ == packet.headers_size()) {
- return;
- }
- rtp_overhead_bytes_per_packet_ = packet.headers_size();
- overhead_bytes_per_packet = rtp_overhead_bytes_per_packet_;
- }
- overhead_observer_->OnOverheadChanged(overhead_bytes_per_packet);
-}
-
int64_t RTPSender::LastTimestampTimeMs() const {
rtc::CritScope lock(&send_critsect_);
return last_timestamp_time_ms_;
diff --git a/modules/rtp_rtcp/source/rtp_sender.h b/modules/rtp_rtcp/source/rtp_sender.h
index 50ece54..c973c7e 100644
--- a/modules/rtp_rtcp/source/rtp_sender.h
+++ b/modules/rtp_rtcp/source/rtp_sender.h
@@ -29,6 +29,7 @@
#include "modules/rtp_rtcp/include/rtp_rtcp_defines.h"
#include "modules/rtp_rtcp/source/rtp_packet_history.h"
#include "modules/rtp_rtcp/source/rtp_rtcp_config.h"
+#include "modules/rtp_rtcp/source/rtp_sender_egress.h"
#include "rtc_base/constructor_magic.h"
#include "rtc_base/critical_section.h"
#include "rtc_base/deprecation.h"
@@ -164,11 +165,6 @@
void OnPacketsAcknowledged(rtc::ArrayView<const uint16_t> sequence_numbers);
private:
- // Maps capture time in milliseconds to send-side delay in milliseconds.
- // Send-side delay is the difference between transmission time and capture
- // time.
- typedef std::map<int64_t, int> SendDelayMap;
-
// Helper class that redirects packets directly to the send part of this class
// without passing through an actual paced sender.
class NonPacedPacketSender : public RtpPacketSender {
@@ -187,30 +183,8 @@
std::unique_ptr<RtpPacketToSend> BuildRtxPacket(
const RtpPacketToSend& packet);
- // Sends packet on to |transport_|, leaving the RTP module.
- bool SendPacketToNetwork(const RtpPacketToSend& packet,
- const PacketOptions& options,
- const PacedPacketInfo& pacing_info);
-
- void RecomputeMaxSendDelay() RTC_EXCLUSIVE_LOCKS_REQUIRED(statistics_crit_);
- void UpdateDelayStatistics(int64_t capture_time_ms,
- int64_t now_ms,
- uint32_t ssrc);
- void UpdateOnSendPacket(int packet_id,
- int64_t capture_time_ms,
- uint32_t ssrc);
-
- void UpdateRtpStats(const RtpPacketToSend& packet,
- bool is_rtx,
- bool is_retransmit);
bool IsFecPacket(const RtpPacketToSend& packet) const;
- void AddPacketToTransportFeedback(uint16_t packet_id,
- const RtpPacketToSend& packet,
- const PacedPacketInfo& pacing_info);
-
- void UpdateRtpOverhead(const RtpPacketToSend& packet);
-
Clock* const clock_;
Random random_ RTC_GUARDED_BY(send_critsect_);
@@ -222,12 +196,9 @@
const std::unique_ptr<NonPacedPacketSender> non_paced_packet_sender_;
RtpPacketSender* const paced_sender_;
- TransportFeedbackObserver* const transport_feedback_observer_;
rtc::CriticalSection send_critsect_;
- Transport* transport_;
bool sending_media_ RTC_GUARDED_BY(send_critsect_);
- bool force_part_of_allocation_ RTC_GUARDED_BY(send_critsect_);
size_t max_packet_size_;
int8_t last_payload_type_ RTC_GUARDED_BY(send_critsect_);
@@ -237,24 +208,6 @@
RtpPacketHistory packet_history_;
- // Statistics
- rtc::CriticalSection statistics_crit_;
- SendDelayMap send_delays_ RTC_GUARDED_BY(statistics_crit_);
- SendDelayMap::const_iterator max_delay_it_ RTC_GUARDED_BY(statistics_crit_);
- // The sum of delays over a kSendSideDelayWindowMs sliding window.
- int64_t sum_delays_ms_ RTC_GUARDED_BY(statistics_crit_);
- // The sum of delays of all packets sent.
- uint64_t total_packet_send_delay_ms_ RTC_GUARDED_BY(statistics_crit_);
- StreamDataCounters rtp_stats_ RTC_GUARDED_BY(statistics_crit_);
- StreamDataCounters rtx_rtp_stats_ RTC_GUARDED_BY(statistics_crit_);
- StreamDataCountersCallback* const rtp_stats_callback_;
- RateStatistics total_bitrate_sent_ RTC_GUARDED_BY(statistics_crit_);
- RateStatistics nack_bitrate_sent_ RTC_GUARDED_BY(statistics_crit_);
- SendSideDelayObserver* const send_side_delay_observer_;
- RtcEventLog* const event_log_;
- SendPacketObserver* const send_packet_observer_;
- BitrateStatisticsObserver* const bitrate_callback_;
-
// RTP variables
uint32_t timestamp_offset_ RTC_GUARDED_BY(send_critsect_);
bool sequence_number_forced_ RTC_GUARDED_BY(send_critsect_);
@@ -271,20 +224,16 @@
uint32_t last_rtp_timestamp_ RTC_GUARDED_BY(send_critsect_);
int64_t capture_time_ms_ RTC_GUARDED_BY(send_critsect_);
int64_t last_timestamp_time_ms_ RTC_GUARDED_BY(send_critsect_);
- bool media_has_been_sent_ RTC_GUARDED_BY(send_critsect_);
bool last_packet_marker_bit_ RTC_GUARDED_BY(send_critsect_);
std::vector<uint32_t> csrcs_ RTC_GUARDED_BY(send_critsect_);
int rtx_ RTC_GUARDED_BY(send_critsect_);
// Mapping rtx_payload_type_map_[associated] = rtx.
std::map<int8_t, int8_t> rtx_payload_type_map_ RTC_GUARDED_BY(send_critsect_);
- size_t rtp_overhead_bytes_per_packet_ RTC_GUARDED_BY(send_critsect_);
bool supports_bwe_extension_ RTC_GUARDED_BY(send_critsect_);
RateLimiter* const retransmission_rate_limiter_;
- OverheadObserver* overhead_observer_;
- const bool populate_network2_timestamp_;
- const bool send_side_bwe_with_overhead_;
+ RtpSenderEgress egress_;
RTC_DISALLOW_IMPLICIT_CONSTRUCTORS(RTPSender);
};
diff --git a/modules/rtp_rtcp/source/rtp_sender_egress.cc b/modules/rtp_rtcp/source/rtp_sender_egress.cc
new file mode 100644
index 0000000..3782f7c
--- /dev/null
+++ b/modules/rtp_rtcp/source/rtp_sender_egress.cc
@@ -0,0 +1,392 @@
+/*
+ * Copyright (c) 2019 The WebRTC project authors. All Rights Reserved.
+ *
+ * Use of this source code is governed by a BSD-style license
+ * that can be found in the LICENSE file in the root of the source
+ * tree. An additional intellectual property rights grant can be found
+ * in the file PATENTS. All contributing project authors may
+ * be found in the AUTHORS file in the root of the source tree.
+ */
+
+#include "modules/rtp_rtcp/source/rtp_sender_egress.h"
+
+#include <limits>
+#include <memory>
+#include <utility>
+
+#include "absl/strings/match.h"
+#include "api/transport/field_trial_based_config.h"
+#include "logging/rtc_event_log/events/rtc_event_rtp_packet_outgoing.h"
+#include "rtc_base/logging.h"
+
+namespace webrtc {
+namespace {
+constexpr uint32_t kTimestampTicksPerMs = 90;
+constexpr int kSendSideDelayWindowMs = 1000;
+constexpr int kBitrateStatisticsWindowMs = 1000;
+
+bool IsEnabled(absl::string_view name,
+ const WebRtcKeyValueConfig* field_trials) {
+ FieldTrialBasedConfig default_trials;
+ auto& trials = field_trials ? *field_trials : default_trials;
+ return absl::StartsWith(trials.Lookup(name), "Enabled");
+}
+} // namespace
+
+RtpSenderEgress::RtpSenderEgress(const RtpRtcp::Configuration& config,
+ RtpPacketHistory* packet_history,
+ Clock* clock)
+ : ssrc_(config.local_media_ssrc),
+ rtx_ssrc_(config.rtx_send_ssrc),
+ flexfec_ssrc_(config.flexfec_sender
+ ? absl::make_optional(config.flexfec_sender->ssrc())
+ : absl::nullopt),
+ populate_network2_timestamp_(config.populate_network2_timestamp),
+ send_side_bwe_with_overhead_(
+ IsEnabled("WebRTC-SendSideBwe-WithOverhead", config.field_trials)),
+ clock_(clock),
+ packet_history_(packet_history),
+ transport_(config.outgoing_transport),
+ event_log_(config.event_log),
+ transport_feedback_observer_(config.transport_feedback_callback),
+ send_side_delay_observer_(config.send_side_delay_observer),
+ send_packet_observer_(config.send_packet_observer),
+ overhead_observer_(config.overhead_observer),
+ rtp_stats_callback_(config.rtp_stats_callback),
+ bitrate_callback_(config.send_bitrate_observer),
+ media_has_been_sent_(false),
+ force_part_of_allocation_(false),
+ max_delay_it_(send_delays_.end()),
+ sum_delays_ms_(0),
+ total_packet_send_delay_ms_(0),
+ rtp_overhead_bytes_per_packet_(0),
+ total_bitrate_sent_(kBitrateStatisticsWindowMs,
+ RateStatistics::kBpsScale),
+ nack_bitrate_sent_(kBitrateStatisticsWindowMs,
+ RateStatistics::kBpsScale) {}
+
+void RtpSenderEgress::SendPacket(RtpPacketToSend* packet,
+ const PacedPacketInfo& pacing_info) {
+ RTC_DCHECK(packet);
+
+ const uint32_t packet_ssrc = packet->Ssrc();
+ RTC_DCHECK(packet->packet_type().has_value());
+ RTC_DCHECK(HasCorrectSsrc(*packet));
+
+ PacketOptions options;
+ {
+ rtc::CritScope lock(&lock_);
+ options.included_in_allocation = force_part_of_allocation_;
+ }
+
+ // Bug webrtc:7859. While FEC is invoked from rtp_sender_video, and not after
+ // the pacer, these modifications of the header below are happening after the
+ // FEC protection packets are calculated. This will corrupt recovered packets
+ // at the same place. It's not an issue for extensions, which are present in
+ // all the packets (their content just may be incorrect on recovered packets).
+ // In case of VideoTimingExtension, since it's present not in every packet,
+ // data after rtp header may be corrupted if these packets are protected by
+ // the FEC.
+ int64_t now_ms = clock_->TimeInMilliseconds();
+ int64_t diff_ms = now_ms - packet->capture_time_ms();
+ if (packet->IsExtensionReserved<TransmissionOffset>()) {
+ packet->SetExtension<TransmissionOffset>(kTimestampTicksPerMs * diff_ms);
+ }
+ if (packet->IsExtensionReserved<AbsoluteSendTime>()) {
+ packet->SetExtension<AbsoluteSendTime>(
+ AbsoluteSendTime::MsTo24Bits(now_ms));
+ }
+
+ if (packet->HasExtension<VideoTimingExtension>()) {
+ if (populate_network2_timestamp_) {
+ packet->set_network2_time_ms(now_ms);
+ } else {
+ packet->set_pacer_exit_time_ms(now_ms);
+ }
+ }
+
+ const bool is_media =
+ packet->packet_type() == RtpPacketToSend::Type::kAudio ||
+ packet->packet_type() == RtpPacketToSend::Type::kVideo;
+
+ // Downstream code actually uses this flag to distinguish between media and
+ // everything else.
+ options.is_retransmit = !is_media;
+ if (auto packet_id = packet->GetExtension<TransportSequenceNumber>()) {
+ options.packet_id = *packet_id;
+ options.included_in_feedback = true;
+ options.included_in_allocation = true;
+ AddPacketToTransportFeedback(*packet_id, *packet, pacing_info);
+ }
+
+ options.application_data.assign(packet->application_data().begin(),
+ packet->application_data().end());
+
+ if (packet->packet_type() != RtpPacketToSend::Type::kPadding &&
+ packet->packet_type() != RtpPacketToSend::Type::kRetransmission) {
+ UpdateDelayStatistics(packet->capture_time_ms(), now_ms, packet_ssrc);
+ UpdateOnSendPacket(options.packet_id, packet->capture_time_ms(),
+ packet_ssrc);
+ }
+
+ const bool send_success = SendPacketToNetwork(*packet, options, pacing_info);
+
+ // Put packet in retransmission history or update pending status even if
+ // actual sending fails.
+ if (is_media && packet->allow_retransmission()) {
+ packet_history_->PutRtpPacket(std::make_unique<RtpPacketToSend>(*packet),
+ now_ms);
+ } else if (packet->retransmitted_sequence_number()) {
+ packet_history_->MarkPacketAsSent(*packet->retransmitted_sequence_number());
+ }
+
+ if (send_success) {
+ rtc::CritScope lock(&lock_);
+ UpdateRtpStats(*packet);
+ media_has_been_sent_ = true;
+ }
+}
+
+void RtpSenderEgress::ProcessBitrateAndNotifyObservers() {
+ if (!bitrate_callback_)
+ return;
+
+ rtc::CritScope lock(&lock_);
+ int64_t now_ms = clock_->TimeInMilliseconds();
+ bitrate_callback_->Notify(total_bitrate_sent_.Rate(now_ms).value_or(0),
+ nack_bitrate_sent_.Rate(now_ms).value_or(0), ssrc_);
+}
+
+DataRate RtpSenderEgress::SendBitrate() const {
+ rtc::CritScope cs(&lock_);
+ return DataRate::bps(
+ total_bitrate_sent_.Rate(clock_->TimeInMilliseconds()).value_or(0));
+}
+
+DataRate RtpSenderEgress::NackOverheadRate() const {
+ rtc::CritScope cs(&lock_);
+ return DataRate::bps(
+ nack_bitrate_sent_.Rate(clock_->TimeInMilliseconds()).value_or(0));
+}
+
+void RtpSenderEgress::GetDataCounters(StreamDataCounters* rtp_stats,
+ StreamDataCounters* rtx_stats) const {
+ rtc::CritScope lock(&lock_);
+ *rtp_stats = rtp_stats_;
+ *rtx_stats = rtx_rtp_stats_;
+}
+
+void RtpSenderEgress::ForceIncludeSendPacketsInAllocation(
+ bool part_of_allocation) {
+ rtc::CritScope lock(&lock_);
+ force_part_of_allocation_ = part_of_allocation;
+}
+
+bool RtpSenderEgress::MediaHasBeenSent() const {
+ rtc::CritScope lock(&lock_);
+ return media_has_been_sent_;
+}
+
+void RtpSenderEgress::SetMediaHasBeenSent(bool media_sent) {
+ rtc::CritScope lock(&lock_);
+ media_has_been_sent_ = media_sent;
+}
+
+bool RtpSenderEgress::HasCorrectSsrc(const RtpPacketToSend& packet) const {
+ switch (*packet.packet_type()) {
+ case RtpPacketToSend::Type::kAudio:
+ case RtpPacketToSend::Type::kVideo:
+ return packet.Ssrc() == ssrc_;
+ case RtpPacketToSend::Type::kRetransmission:
+ case RtpPacketToSend::Type::kPadding:
+ // Both padding and retransmission must be on either the media or the
+ // RTX stream.
+ return packet.Ssrc() == rtx_ssrc_ || packet.Ssrc() == ssrc_;
+ case RtpPacketToSend::Type::kForwardErrorCorrection:
+ // FlexFEC is on separate SSRC, ULPFEC uses media SSRC.
+ return packet.Ssrc() == ssrc_ || packet.Ssrc() == flexfec_ssrc_;
+ }
+ return false;
+}
+
+void RtpSenderEgress::AddPacketToTransportFeedback(
+ uint16_t packet_id,
+ const RtpPacketToSend& packet,
+ const PacedPacketInfo& pacing_info) {
+ if (transport_feedback_observer_) {
+ size_t packet_size = packet.payload_size() + packet.padding_size();
+ if (send_side_bwe_with_overhead_) {
+ packet_size = packet.size();
+ }
+
+ RtpPacketSendInfo packet_info;
+ packet_info.ssrc = ssrc_;
+ packet_info.transport_sequence_number = packet_id;
+ packet_info.has_rtp_sequence_number = true;
+ packet_info.rtp_sequence_number = packet.SequenceNumber();
+ packet_info.length = packet_size;
+ packet_info.pacing_info = pacing_info;
+ transport_feedback_observer_->OnAddPacket(packet_info);
+ }
+}
+
+void RtpSenderEgress::UpdateDelayStatistics(int64_t capture_time_ms,
+ int64_t now_ms,
+ uint32_t ssrc) {
+ if (!send_side_delay_observer_ || capture_time_ms <= 0)
+ return;
+
+ int avg_delay_ms = 0;
+ int max_delay_ms = 0;
+ uint64_t total_packet_send_delay_ms = 0;
+ {
+ rtc::CritScope cs(&lock_);
+ // Compute the max and average of the recent capture-to-send delays.
+ // The time complexity of the current approach depends on the distribution
+ // of the delay values. This could be done more efficiently.
+
+ // Remove elements older than kSendSideDelayWindowMs.
+ auto lower_bound =
+ send_delays_.lower_bound(now_ms - kSendSideDelayWindowMs);
+ for (auto it = send_delays_.begin(); it != lower_bound; ++it) {
+ if (max_delay_it_ == it) {
+ max_delay_it_ = send_delays_.end();
+ }
+ sum_delays_ms_ -= it->second;
+ }
+ send_delays_.erase(send_delays_.begin(), lower_bound);
+ if (max_delay_it_ == send_delays_.end()) {
+ // Removed the previous max. Need to recompute.
+ RecomputeMaxSendDelay();
+ }
+
+ // Add the new element.
+ RTC_DCHECK_GE(now_ms, 0);
+ RTC_DCHECK_LE(now_ms, std::numeric_limits<int64_t>::max() / 2);
+ RTC_DCHECK_GE(capture_time_ms, 0);
+ RTC_DCHECK_LE(capture_time_ms, std::numeric_limits<int64_t>::max() / 2);
+ int64_t diff_ms = now_ms - capture_time_ms;
+ RTC_DCHECK_GE(diff_ms, static_cast<int64_t>(0));
+ RTC_DCHECK_LE(diff_ms, std::numeric_limits<int>::max());
+ int new_send_delay = rtc::dchecked_cast<int>(now_ms - capture_time_ms);
+ SendDelayMap::iterator it;
+ bool inserted;
+ std::tie(it, inserted) =
+ send_delays_.insert(std::make_pair(now_ms, new_send_delay));
+ if (!inserted) {
+ // TODO(terelius): If we have multiple delay measurements during the same
+ // millisecond then we keep the most recent one. It is not clear that this
+ // is the right decision, but it preserves an earlier behavior.
+ int previous_send_delay = it->second;
+ sum_delays_ms_ -= previous_send_delay;
+ it->second = new_send_delay;
+ if (max_delay_it_ == it && new_send_delay < previous_send_delay) {
+ RecomputeMaxSendDelay();
+ }
+ }
+ if (max_delay_it_ == send_delays_.end() ||
+ it->second >= max_delay_it_->second) {
+ max_delay_it_ = it;
+ }
+ sum_delays_ms_ += new_send_delay;
+ total_packet_send_delay_ms_ += new_send_delay;
+ total_packet_send_delay_ms = total_packet_send_delay_ms_;
+
+ size_t num_delays = send_delays_.size();
+ RTC_DCHECK(max_delay_it_ != send_delays_.end());
+ max_delay_ms = rtc::dchecked_cast<int>(max_delay_it_->second);
+ int64_t avg_ms = (sum_delays_ms_ + num_delays / 2) / num_delays;
+ RTC_DCHECK_GE(avg_ms, static_cast<int64_t>(0));
+ RTC_DCHECK_LE(avg_ms,
+ static_cast<int64_t>(std::numeric_limits<int>::max()));
+ avg_delay_ms =
+ rtc::dchecked_cast<int>((sum_delays_ms_ + num_delays / 2) / num_delays);
+ }
+ send_side_delay_observer_->SendSideDelayUpdated(
+ avg_delay_ms, max_delay_ms, total_packet_send_delay_ms, ssrc);
+}
+
+void RtpSenderEgress::RecomputeMaxSendDelay() {
+ max_delay_it_ = send_delays_.begin();
+ for (auto it = send_delays_.begin(); it != send_delays_.end(); ++it) {
+ if (it->second >= max_delay_it_->second) {
+ max_delay_it_ = it;
+ }
+ }
+}
+
+void RtpSenderEgress::UpdateOnSendPacket(int packet_id,
+ int64_t capture_time_ms,
+ uint32_t ssrc) {
+ if (!send_packet_observer_ || capture_time_ms <= 0 || packet_id == -1) {
+ return;
+ }
+
+ send_packet_observer_->OnSendPacket(packet_id, capture_time_ms, ssrc);
+}
+
+bool RtpSenderEgress::SendPacketToNetwork(const RtpPacketToSend& packet,
+ const PacketOptions& options,
+ const PacedPacketInfo& pacing_info) {
+ int bytes_sent = -1;
+ if (transport_) {
+ UpdateRtpOverhead(packet);
+ bytes_sent = transport_->SendRtp(packet.data(), packet.size(), options)
+ ? static_cast<int>(packet.size())
+ : -1;
+ if (event_log_ && bytes_sent > 0) {
+ event_log_->Log(std::make_unique<RtcEventRtpPacketOutgoing>(
+ packet, pacing_info.probe_cluster_id));
+ }
+ }
+
+ if (bytes_sent <= 0) {
+ RTC_LOG(LS_WARNING) << "Transport failed to send packet.";
+ return false;
+ }
+ return true;
+}
+
+void RtpSenderEgress::UpdateRtpOverhead(const RtpPacketToSend& packet) {
+ if (!overhead_observer_)
+ return;
+ size_t overhead_bytes_per_packet;
+ {
+ rtc::CritScope lock(&lock_);
+ if (rtp_overhead_bytes_per_packet_ == packet.headers_size()) {
+ return;
+ }
+ rtp_overhead_bytes_per_packet_ = packet.headers_size();
+ overhead_bytes_per_packet = rtp_overhead_bytes_per_packet_;
+ }
+ overhead_observer_->OnOverheadChanged(overhead_bytes_per_packet);
+}
+
+void RtpSenderEgress::UpdateRtpStats(const RtpPacketToSend& packet) {
+ int64_t now_ms = clock_->TimeInMilliseconds();
+
+ StreamDataCounters* counters =
+ packet.Ssrc() == rtx_ssrc_ ? &rtx_rtp_stats_ : &rtp_stats_;
+
+ total_bitrate_sent_.Update(packet.size(), now_ms);
+
+ if (counters->first_packet_time_ms == -1) {
+ counters->first_packet_time_ms = now_ms;
+ }
+
+ if (packet.packet_type() == RtpPacketToSend::Type::kForwardErrorCorrection) {
+ counters->fec.AddPacket(packet);
+ }
+
+ if (packet.packet_type() == RtpPacketToSend::Type::kRetransmission) {
+ counters->retransmitted.AddPacket(packet);
+ nack_bitrate_sent_.Update(packet.size(), now_ms);
+ }
+ counters->transmitted.AddPacket(packet);
+
+ if (rtp_stats_callback_) {
+ rtp_stats_callback_->DataCountersUpdated(*counters, packet.Ssrc());
+ }
+}
+
+} // namespace webrtc
diff --git a/modules/rtp_rtcp/source/rtp_sender_egress.h b/modules/rtp_rtcp/source/rtp_sender_egress.h
new file mode 100644
index 0000000..baa2227
--- /dev/null
+++ b/modules/rtp_rtcp/source/rtp_sender_egress.h
@@ -0,0 +1,112 @@
+/*
+ * Copyright (c) 2019 The WebRTC project authors. All Rights Reserved.
+ *
+ * Use of this source code is governed by a BSD-style license
+ * that can be found in the LICENSE file in the root of the source
+ * tree. An additional intellectual property rights grant can be found
+ * in the file PATENTS. All contributing project authors may
+ * be found in the AUTHORS file in the root of the source tree.
+ */
+
+#ifndef MODULES_RTP_RTCP_SOURCE_RTP_SENDER_EGRESS_H_
+#define MODULES_RTP_RTCP_SOURCE_RTP_SENDER_EGRESS_H_
+
+#include <map>
+
+#include "absl/types/optional.h"
+#include "api/call/transport.h"
+#include "api/rtc_event_log/rtc_event_log.h"
+#include "api/units/data_rate.h"
+#include "modules/rtp_rtcp/include/rtp_rtcp.h"
+#include "modules/rtp_rtcp/include/rtp_rtcp_defines.h"
+#include "modules/rtp_rtcp/source/rtp_packet_history.h"
+#include "modules/rtp_rtcp/source/rtp_packet_to_send.h"
+#include "rtc_base/critical_section.h"
+#include "rtc_base/rate_statistics.h"
+#include "rtc_base/thread_annotations.h"
+
+namespace webrtc {
+
+class RtpSenderEgress {
+ public:
+ explicit RtpSenderEgress(const RtpRtcp::Configuration& config,
+ RtpPacketHistory* packet_history,
+ Clock* clock);
+ ~RtpSenderEgress() = default;
+
+ void SendPacket(RtpPacketToSend* packet, const PacedPacketInfo& pacing_info);
+ uint32_t Ssrc() const { return ssrc_; }
+ absl::optional<uint32_t> RtxSsrc() const { return rtx_ssrc_; }
+ absl::optional<uint32_t> FlexFecSsrc() const { return flexfec_ssrc_; }
+
+ void ProcessBitrateAndNotifyObservers();
+ DataRate SendBitrate() const;
+ DataRate NackOverheadRate() const;
+ void GetDataCounters(StreamDataCounters* rtp_stats,
+ StreamDataCounters* rtx_stats) const;
+
+ void ForceIncludeSendPacketsInAllocation(bool part_of_allocation);
+ bool MediaHasBeenSent() const;
+ void SetMediaHasBeenSent(bool media_sent);
+
+ private:
+ // Maps capture time in milliseconds to send-side delay in milliseconds.
+ // Send-side delay is the difference between transmission time and capture
+ // time.
+ typedef std::map<int64_t, int> SendDelayMap;
+
+ bool HasCorrectSsrc(const RtpPacketToSend& packet) const;
+ void AddPacketToTransportFeedback(uint16_t packet_id,
+ const RtpPacketToSend& packet,
+ const PacedPacketInfo& pacing_info);
+ void UpdateDelayStatistics(int64_t capture_time_ms,
+ int64_t now_ms,
+ uint32_t ssrc);
+ void RecomputeMaxSendDelay() RTC_EXCLUSIVE_LOCKS_REQUIRED(lock_);
+ void UpdateOnSendPacket(int packet_id,
+ int64_t capture_time_ms,
+ uint32_t ssrc);
+ // Sends packet on to |transport_|, leaving the RTP module.
+ bool SendPacketToNetwork(const RtpPacketToSend& packet,
+ const PacketOptions& options,
+ const PacedPacketInfo& pacing_info);
+ void UpdateRtpOverhead(const RtpPacketToSend& packet);
+ void UpdateRtpStats(const RtpPacketToSend& packet)
+ RTC_EXCLUSIVE_LOCKS_REQUIRED(lock_);
+
+ const uint32_t ssrc_;
+ const absl::optional<uint32_t> rtx_ssrc_;
+ const absl::optional<uint32_t> flexfec_ssrc_;
+ const bool populate_network2_timestamp_;
+ const bool send_side_bwe_with_overhead_;
+ Clock* const clock_;
+ RtpPacketHistory* const packet_history_;
+ Transport* const transport_;
+ RtcEventLog* const event_log_;
+
+ TransportFeedbackObserver* const transport_feedback_observer_;
+ SendSideDelayObserver* const send_side_delay_observer_;
+ SendPacketObserver* const send_packet_observer_;
+ OverheadObserver* const overhead_observer_;
+ StreamDataCountersCallback* const rtp_stats_callback_;
+ BitrateStatisticsObserver* const bitrate_callback_;
+
+ rtc::CriticalSection lock_;
+ bool media_has_been_sent_ RTC_GUARDED_BY(lock_);
+ bool force_part_of_allocation_ RTC_GUARDED_BY(lock_);
+
+ SendDelayMap send_delays_ RTC_GUARDED_BY(lock_);
+ SendDelayMap::const_iterator max_delay_it_ RTC_GUARDED_BY(lock_);
+ // The sum of delays over a kSendSideDelayWindowMs sliding window.
+ int64_t sum_delays_ms_ RTC_GUARDED_BY(lock_);
+ uint64_t total_packet_send_delay_ms_ RTC_GUARDED_BY(lock_);
+ size_t rtp_overhead_bytes_per_packet_ RTC_GUARDED_BY(lock_);
+ StreamDataCounters rtp_stats_ RTC_GUARDED_BY(lock_);
+ StreamDataCounters rtx_rtp_stats_ RTC_GUARDED_BY(lock_);
+ RateStatistics total_bitrate_sent_ RTC_GUARDED_BY(lock_);
+ RateStatistics nack_bitrate_sent_ RTC_GUARDED_BY(lock_);
+};
+
+} // namespace webrtc
+
+#endif // MODULES_RTP_RTCP_SOURCE_RTP_SENDER_EGRESS_H_
diff --git a/modules/rtp_rtcp/source/rtp_sender_unittest.cc b/modules/rtp_rtcp/source/rtp_sender_unittest.cc
index 1cd3ea4..a411b79 100644
--- a/modules/rtp_rtcp/source/rtp_sender_unittest.cc
+++ b/modules/rtp_rtcp/source/rtp_sender_unittest.cc
@@ -2043,15 +2043,12 @@
BuildRtpPacket(kPayload, true, 0, fake_clock_.TimeInMilliseconds());
packet->set_packet_type(RtpPacketToSend::Type::kVideo);
- // Verify not sent with wrong SSRC.
- packet->SetSsrc(kSsrc + 1);
- EXPECT_FALSE(rtp_sender_->TrySendPacket(packet.get(), PacedPacketInfo()));
-
// Verify sent with correct SSRC.
packet = BuildRtpPacket(kPayload, true, 0, fake_clock_.TimeInMilliseconds());
packet->SetSsrc(kSsrc);
packet->set_packet_type(RtpPacketToSend::Type::kVideo);
- EXPECT_TRUE(rtp_sender_->TrySendPacket(packet.get(), PacedPacketInfo()));
+ rtp_sender_->TrySendPacket(packet.get(), PacedPacketInfo());
+ EXPECT_EQ(transport_.packets_sent(), 1);
}
TEST_P(RtpSenderTest, TrySendPacketMatchesAudio) {
@@ -2059,15 +2056,12 @@
BuildRtpPacket(kPayload, true, 0, fake_clock_.TimeInMilliseconds());
packet->set_packet_type(RtpPacketToSend::Type::kAudio);
- // Verify not sent with wrong SSRC.
- packet->SetSsrc(kSsrc + 1);
- EXPECT_FALSE(rtp_sender_->TrySendPacket(packet.get(), PacedPacketInfo()));
-
// Verify sent with correct SSRC.
packet = BuildRtpPacket(kPayload, true, 0, fake_clock_.TimeInMilliseconds());
packet->SetSsrc(kSsrc);
packet->set_packet_type(RtpPacketToSend::Type::kAudio);
- EXPECT_TRUE(rtp_sender_->TrySendPacket(packet.get(), PacedPacketInfo()));
+ rtp_sender_->TrySendPacket(packet.get(), PacedPacketInfo());
+ EXPECT_EQ(transport_.packets_sent(), 1);
}
TEST_P(RtpSenderTest, TrySendPacketMatchesRetransmissions) {
@@ -2075,21 +2069,19 @@
BuildRtpPacket(kPayload, true, 0, fake_clock_.TimeInMilliseconds());
packet->set_packet_type(RtpPacketToSend::Type::kRetransmission);
- // Verify not sent with wrong SSRC.
- packet->SetSsrc(kSsrc + 1);
- EXPECT_FALSE(rtp_sender_->TrySendPacket(packet.get(), PacedPacketInfo()));
-
// Verify sent with correct SSRC (non-RTX).
packet = BuildRtpPacket(kPayload, true, 0, fake_clock_.TimeInMilliseconds());
packet->SetSsrc(kSsrc);
packet->set_packet_type(RtpPacketToSend::Type::kRetransmission);
- EXPECT_TRUE(rtp_sender_->TrySendPacket(packet.get(), PacedPacketInfo()));
+ rtp_sender_->TrySendPacket(packet.get(), PacedPacketInfo());
+ EXPECT_EQ(transport_.packets_sent(), 1);
// RTX retransmission.
packet = BuildRtpPacket(kPayload, true, 0, fake_clock_.TimeInMilliseconds());
packet->SetSsrc(kRtxSsrc);
packet->set_packet_type(RtpPacketToSend::Type::kRetransmission);
- EXPECT_TRUE(rtp_sender_->TrySendPacket(packet.get(), PacedPacketInfo()));
+ rtp_sender_->TrySendPacket(packet.get(), PacedPacketInfo());
+ EXPECT_EQ(transport_.packets_sent(), 2);
}
TEST_P(RtpSenderTest, TrySendPacketMatchesPadding) {
@@ -2097,21 +2089,19 @@
BuildRtpPacket(kPayload, true, 0, fake_clock_.TimeInMilliseconds());
packet->set_packet_type(RtpPacketToSend::Type::kPadding);
- // Verify not sent with wrong SSRC.
- packet->SetSsrc(kSsrc + 1);
- EXPECT_FALSE(rtp_sender_->TrySendPacket(packet.get(), PacedPacketInfo()));
-
// Verify sent with correct SSRC (non-RTX).
packet = BuildRtpPacket(kPayload, true, 0, fake_clock_.TimeInMilliseconds());
packet->SetSsrc(kSsrc);
packet->set_packet_type(RtpPacketToSend::Type::kPadding);
- EXPECT_TRUE(rtp_sender_->TrySendPacket(packet.get(), PacedPacketInfo()));
+ rtp_sender_->TrySendPacket(packet.get(), PacedPacketInfo());
+ EXPECT_EQ(transport_.packets_sent(), 1);
// RTX padding.
packet = BuildRtpPacket(kPayload, true, 0, fake_clock_.TimeInMilliseconds());
packet->SetSsrc(kRtxSsrc);
packet->set_packet_type(RtpPacketToSend::Type::kPadding);
- EXPECT_TRUE(rtp_sender_->TrySendPacket(packet.get(), PacedPacketInfo()));
+ rtp_sender_->TrySendPacket(packet.get(), PacedPacketInfo());
+ EXPECT_EQ(transport_.packets_sent(), 2);
}
TEST_P(RtpSenderTest, TrySendPacketMatchesFlexfec) {
@@ -2119,15 +2109,12 @@
BuildRtpPacket(kPayload, true, 0, fake_clock_.TimeInMilliseconds());
packet->set_packet_type(RtpPacketToSend::Type::kForwardErrorCorrection);
- // Verify not sent with wrong SSRC.
- packet->SetSsrc(kSsrc + 1);
- EXPECT_FALSE(rtp_sender_->TrySendPacket(packet.get(), PacedPacketInfo()));
-
// Verify sent with correct SSRC.
packet = BuildRtpPacket(kPayload, true, 0, fake_clock_.TimeInMilliseconds());
packet->SetSsrc(kFlexFecSsrc);
packet->set_packet_type(RtpPacketToSend::Type::kForwardErrorCorrection);
- EXPECT_TRUE(rtp_sender_->TrySendPacket(packet.get(), PacedPacketInfo()));
+ rtp_sender_->TrySendPacket(packet.get(), PacedPacketInfo());
+ EXPECT_EQ(transport_.packets_sent(), 1);
}
TEST_P(RtpSenderTest, TrySendPacketMatchesUlpfec) {
@@ -2135,15 +2122,12 @@
BuildRtpPacket(kPayload, true, 0, fake_clock_.TimeInMilliseconds());
packet->set_packet_type(RtpPacketToSend::Type::kForwardErrorCorrection);
- // Verify not sent with wrong SSRC.
- packet->SetSsrc(kSsrc + 1);
- EXPECT_FALSE(rtp_sender_->TrySendPacket(packet.get(), PacedPacketInfo()));
-
// Verify sent with correct SSRC.
packet = BuildRtpPacket(kPayload, true, 0, fake_clock_.TimeInMilliseconds());
packet->SetSsrc(kSsrc);
packet->set_packet_type(RtpPacketToSend::Type::kForwardErrorCorrection);
- EXPECT_TRUE(rtp_sender_->TrySendPacket(packet.get(), PacedPacketInfo()));
+ rtp_sender_->TrySendPacket(packet.get(), PacedPacketInfo());
+ EXPECT_EQ(transport_.packets_sent(), 1);
}
TEST_P(RtpSenderTest, TrySendPacketHandlesRetransmissionHistory) {