From 671b40330465ede00e0955fa1fdc495ade6ff944 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Erik=20Spr=C3=A5ng?= Date: Thu, 17 Oct 2019 16:56:22 +0200 Subject: [PATCH] Split RTPSender into pre- and post-pacer parts. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 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 Commit-Queue: Erik Språng Cr-Commit-Position: refs/heads/master@{#29519} --- modules/rtp_rtcp/BUILD.gn | 3 + modules/rtp_rtcp/source/rtp_sender.cc | 351 +--------------- modules/rtp_rtcp/source/rtp_sender.h | 55 +-- modules/rtp_rtcp/source/rtp_sender_egress.cc | 392 ++++++++++++++++++ modules/rtp_rtcp/source/rtp_sender_egress.h | 112 +++++ .../rtp_rtcp/source/rtp_sender_unittest.cc | 48 +-- 6 files changed, 537 insertions(+), 424 deletions(-) create mode 100644 modules/rtp_rtcp/source/rtp_sender_egress.cc create mode 100644 modules/rtp_rtcp/source/rtp_sender_egress.h diff --git a/modules/rtp_rtcp/BUILD.gn b/modules/rtp_rtcp/BUILD.gn index 3d7eeabf10..f42110097f 100644 --- a/modules/rtp_rtcp/BUILD.gn +++ b/modules/rtp_rtcp/BUILD.gn @@ -185,6 +185,8 @@ rtc_static_library("rtp_rtcp") { "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 @@ rtc_static_library("rtp_rtcp") { "../../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 c9555fa767..e2f57febbb 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 @@ namespace { // 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 @@ constexpr RtpExtensionSize kVideoExtensionSizes[] = { 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 @@ RTPSender::RTPSender(const RtpRtcp::Configuration& config) 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 @@ RTPSender::RTPSender(const RtpRtcp::Configuration& config) 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(); // Random start, 16 bits. Can't be 0. @@ -203,15 +172,11 @@ rtc::ArrayView RTPSender::VideoExtensionSizes() { } uint16_t RTPSender::ActualSendBitrateKbit() const { - rtc::CritScope cs(&statistics_crit_); - return static_cast( - total_bitrate_sent_.Rate(clock_->TimeInMilliseconds()).value_or(0) / - 1000); + return egress_.SendBitrate().kbps(); } uint32_t RTPSender::NackOverheadRate() const { - rtc::CritScope cs(&statistics_crit_); - return nack_bitrate_sent_.Rate(clock_->TimeInMilliseconds()).value_or(0); + return egress_.NackOverheadRate().bps(); } void RTPSender::SetExtmapAllowMixed(bool extmap_allow_mixed) { @@ -356,28 +321,6 @@ void RTPSender::OnReceivedAckOnRtxSsrc( 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(packet.size()) - : -1; - if (event_log_ && bytes_sent > 0) { - event_log_->Log(std::make_unique( - 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& nack_sequence_numbers, int64_t avg_rtt) { @@ -398,116 +341,14 @@ bool RTPSender::TrySendPacket(RtpPacketToSend* packet, 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()) { - packet->SetExtension(kTimestampTicksPerMs * diff_ms); - } - if (packet->IsExtensionReserved()) { - packet->SetExtension( - AbsoluteSendTime::MsTo24Bits(now_ms)); - } - - if (packet->HasExtension()) { - 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()) { - 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(*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 @@ bool RTPSender::SupportsRtxPayloadPadding() const { (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> RTPSender::GeneratePadding( size_t target_size_bytes) { // This method does not actually send packets, it just generates @@ -622,7 +436,7 @@ std::vector> RTPSender::GeneratePadding( // 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 @@ void RTPSender::EnqueuePackets( 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(0)); - RTC_DCHECK_LE(now_ms, std::numeric_limits::max() / 2); - RTC_DCHECK_GE(capture_time_ms, static_cast(0)); - RTC_DCHECK_LE(capture_time_ms, std::numeric_limits::max() / 2); - int64_t diff_ms = now_ms - capture_time_ms; - RTC_DCHECK_GE(diff_ms, static_cast(0)); - RTC_DCHECK_LE(diff_ms, - static_cast(std::numeric_limits::max())); - int new_send_delay = rtc::dchecked_cast(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(max_delay_it_->second); - int64_t avg_ms = (sum_delays_ms_ + num_delays / 2) / num_delays; - RTC_DCHECK_GE(avg_ms, static_cast(0)); - RTC_DCHECK_LE(avg_ms, - static_cast(std::numeric_limits::max())); - avg_delay_ms = - rtc::dchecked_cast((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 @@ uint16_t RTPSender::AllocateSequenceNumber(uint16_t packets_to_send) { 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 RTPSender::AllocatePacket() const { @@ -895,8 +606,7 @@ bool RTPSender::SendingMedia() const { } 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 @@ std::unique_ptr RTPSender::BuildRtxPacket( } uint32_t RTPSender::BitrateSent() const { - rtc::CritScope cs(&statistics_crit_); - return total_bitrate_sent_.Rate(clock_->TimeInMilliseconds()).value_or(0); + return egress_.SendBitrate().bps(); } void RTPSender::SetRtpState(const RtpState& rtp_state) { @@ -1084,8 +793,8 @@ void RTPSender::SetRtpState(const RtpState& rtp_state) { 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 @@ RtpState RTPSender::GetRtpState() const { 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 @@ RtpState RTPSender::GetRtxRtpState() const { 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 50ece5421d..c973c7ef64 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 @@ class RTPSender { void OnPacketsAcknowledged(rtc::ArrayView 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 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 @@ class RTPSender { std::unique_ptr 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 @@ class RTPSender { const std::unique_ptr 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 @@ class RTPSender { 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 @@ class RTPSender { 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 csrcs_ RTC_GUARDED_BY(send_critsect_); int rtx_ RTC_GUARDED_BY(send_critsect_); // Mapping rtx_payload_type_map_[associated] = rtx. std::map 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 0000000000..3782f7c7a5 --- /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 +#include +#include + +#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()) { + packet->SetExtension(kTimestampTicksPerMs * diff_ms); + } + if (packet->IsExtensionReserved()) { + packet->SetExtension( + AbsoluteSendTime::MsTo24Bits(now_ms)); + } + + if (packet->HasExtension()) { + 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()) { + 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(*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::max() / 2); + RTC_DCHECK_GE(capture_time_ms, 0); + RTC_DCHECK_LE(capture_time_ms, std::numeric_limits::max() / 2); + int64_t diff_ms = now_ms - capture_time_ms; + RTC_DCHECK_GE(diff_ms, static_cast(0)); + RTC_DCHECK_LE(diff_ms, std::numeric_limits::max()); + int new_send_delay = rtc::dchecked_cast(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(max_delay_it_->second); + int64_t avg_ms = (sum_delays_ms_ + num_delays / 2) / num_delays; + RTC_DCHECK_GE(avg_ms, static_cast(0)); + RTC_DCHECK_LE(avg_ms, + static_cast(std::numeric_limits::max())); + avg_delay_ms = + rtc::dchecked_cast((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(packet.size()) + : -1; + if (event_log_ && bytes_sent > 0) { + event_log_->Log(std::make_unique( + 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 0000000000..baa2227ca1 --- /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 + +#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 RtxSsrc() const { return rtx_ssrc_; } + absl::optional 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 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 rtx_ssrc_; + const absl::optional 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 1cd3ea46c0..a411b79a33 100644 --- a/modules/rtp_rtcp/source/rtp_sender_unittest.cc +++ b/modules/rtp_rtcp/source/rtp_sender_unittest.cc @@ -2043,15 +2043,12 @@ TEST_P(RtpSenderTest, TrySendPacketMatchesVideo) { 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 @@ TEST_P(RtpSenderTest, TrySendPacketMatchesAudio) { 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 @@ TEST_P(RtpSenderTest, TrySendPacketMatchesRetransmissions) { 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 @@ TEST_P(RtpSenderTest, TrySendPacketMatchesPadding) { 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 @@ TEST_P(RtpSenderTest, TrySendPacketMatchesFlexfec) { 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 @@ TEST_P(RtpSenderTest, TrySendPacketMatchesUlpfec) { 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) {