diff --git a/modules/rtp_rtcp/BUILD.gn b/modules/rtp_rtcp/BUILD.gn index c9a3161111..eda27ba68d 100644 --- a/modules/rtp_rtcp/BUILD.gn +++ b/modules/rtp_rtcp/BUILD.gn @@ -186,6 +186,8 @@ rtc_library("rtp_rtcp") { "source/rtp_rtcp_config.h", "source/rtp_rtcp_impl.cc", "source/rtp_rtcp_impl.h", + "source/rtp_rtcp_impl2.cc", + "source/rtp_rtcp_impl2.h", "source/rtp_sender.cc", "source/rtp_sender.h", "source/rtp_sender_audio.cc", @@ -478,6 +480,7 @@ if (rtc_include_tests) { "source/rtp_packet_history_unittest.cc", "source/rtp_packet_unittest.cc", "source/rtp_packetizer_av1_unittest.cc", + "source/rtp_rtcp_impl2_unittest.cc", "source/rtp_rtcp_impl_unittest.cc", "source/rtp_sender_audio_unittest.cc", "source/rtp_sender_unittest.cc", diff --git a/modules/rtp_rtcp/include/rtp_rtcp.h b/modules/rtp_rtcp/include/rtp_rtcp.h index f91f0d13a3..2db523caaf 100644 --- a/modules/rtp_rtcp/include/rtp_rtcp.h +++ b/modules/rtp_rtcp/include/rtp_rtcp.h @@ -53,8 +53,8 @@ class TransportFeedback; class RtpRtcp : public Module, public RtcpFeedbackSenderInterface { public: struct Configuration { - Configuration(); - Configuration(Configuration&& rhs); + Configuration() = default; + Configuration(Configuration&& rhs) = default; // True for a audio version of the RTP/RTCP module object false will create // a video version. diff --git a/modules/rtp_rtcp/source/rtcp_sender.cc b/modules/rtp_rtcp/source/rtcp_sender.cc index 269a73597c..c12fb68dc3 100644 --- a/modules/rtp_rtcp/source/rtcp_sender.cc +++ b/modules/rtp_rtcp/source/rtcp_sender.cc @@ -33,7 +33,7 @@ #include "modules/rtp_rtcp/source/rtcp_packet/tmmbn.h" #include "modules/rtp_rtcp/source/rtcp_packet/tmmbr.h" #include "modules/rtp_rtcp/source/rtcp_packet/transport_feedback.h" -#include "modules/rtp_rtcp/source/rtp_rtcp_impl.h" +#include "modules/rtp_rtcp/source/rtp_rtcp_impl2.h" #include "modules/rtp_rtcp/source/time_util.h" #include "modules/rtp_rtcp/source/tmmbr_help.h" #include "rtc_base/checks.h" @@ -123,7 +123,7 @@ RTCPSender::FeedbackState::FeedbackState() last_rr_ntp_secs(0), last_rr_ntp_frac(0), remote_sr(0), - module(nullptr) {} + receiver(nullptr) {} RTCPSender::FeedbackState::FeedbackState(const FeedbackState&) = default; @@ -544,7 +544,7 @@ void RTCPSender::SetTargetBitrate(unsigned int target_bitrate) { std::unique_ptr RTCPSender::BuildTMMBR( const RtcpContext& ctx) { - if (ctx.feedback_state_.module == nullptr) + if (ctx.feedback_state_.receiver == nullptr) return nullptr; // Before sending the TMMBR check the received TMMBN, only an owner is // allowed to raise the bitrate: @@ -558,7 +558,7 @@ std::unique_ptr RTCPSender::BuildTMMBR( // will accuire criticalSectionRTCPReceiver_ is a potental deadlock but // since RTCPreceiver is not doing the reverse we should be fine std::vector candidates = - ctx.feedback_state_.module->BoundingSet(&tmmbr_owner); + ctx.feedback_state_.receiver->BoundingSet(&tmmbr_owner); if (!candidates.empty()) { for (const auto& candidate : candidates) { diff --git a/modules/rtp_rtcp/source/rtcp_sender.h b/modules/rtp_rtcp/source/rtcp_sender.h index 7da2546bf7..61081d4c79 100644 --- a/modules/rtp_rtcp/source/rtcp_sender.h +++ b/modules/rtp_rtcp/source/rtcp_sender.h @@ -38,10 +38,10 @@ namespace webrtc { -class ModuleRtpRtcpImpl; +class RTCPReceiver; class RtcEventLog; -class RTCPSender { +class RTCPSender final { public: struct FeedbackState { FeedbackState(); @@ -61,7 +61,7 @@ class RTCPSender { std::vector last_xr_rtis; // Used when generating TMMBR. - ModuleRtpRtcpImpl* module; + RTCPReceiver* receiver; }; explicit RTCPSender(const RtpRtcp::Configuration& config); diff --git a/modules/rtp_rtcp/source/rtcp_sender_unittest.cc b/modules/rtp_rtcp/source/rtcp_sender_unittest.cc index 754ad89327..d187b16431 100644 --- a/modules/rtp_rtcp/source/rtcp_sender_unittest.cc +++ b/modules/rtp_rtcp/source/rtcp_sender_unittest.cc @@ -18,7 +18,7 @@ #include "modules/rtp_rtcp/source/rtcp_packet/bye.h" #include "modules/rtp_rtcp/source/rtcp_packet/common_header.h" #include "modules/rtp_rtcp/source/rtp_packet_received.h" -#include "modules/rtp_rtcp/source/rtp_rtcp_impl.h" +#include "modules/rtp_rtcp/source/rtp_rtcp_impl2.h" #include "modules/rtp_rtcp/source/time_util.h" #include "rtc_base/rate_limiter.h" #include "test/gmock.h" @@ -77,7 +77,7 @@ class RtcpSenderTest : public ::testing::Test { receive_statistics_(ReceiveStatistics::Create(&clock_)), retransmission_rate_limiter_(&clock_, 1000) { RtpRtcp::Configuration configuration = GetDefaultConfig(); - rtp_rtcp_impl_.reset(new ModuleRtpRtcpImpl(configuration)); + rtp_rtcp_impl_.reset(new ModuleRtpRtcpImpl2(configuration)); rtcp_sender_.reset(new RTCPSender(configuration)); rtcp_sender_->SetRemoteSSRC(kRemoteSsrc); rtcp_sender_->SetTimestampOffset(kStartRtpTimestamp); @@ -115,7 +115,7 @@ class RtcpSenderTest : public ::testing::Test { SimulatedClock clock_; TestTransport test_transport_; std::unique_ptr receive_statistics_; - std::unique_ptr rtp_rtcp_impl_; + std::unique_ptr rtp_rtcp_impl_; std::unique_ptr rtcp_sender_; RateLimiter retransmission_rate_limiter_; }; diff --git a/modules/rtp_rtcp/source/rtp_rtcp_impl.cc b/modules/rtp_rtcp/source/rtp_rtcp_impl.cc index 07a04852c7..0bd37ebdd7 100644 --- a/modules/rtp_rtcp/source/rtp_rtcp_impl.cc +++ b/modules/rtp_rtcp/source/rtp_rtcp_impl.cc @@ -48,14 +48,6 @@ ModuleRtpRtcpImpl::RtpSenderContext::RtpSenderContext( &packet_history, config.paced_sender ? config.paced_sender : &non_paced_sender) {} -RtpRtcp::Configuration::Configuration() = default; -RtpRtcp::Configuration::Configuration(Configuration&& rhs) = default; - -std::unique_ptr RtpRtcp::Create(const Configuration& configuration) { - RTC_DCHECK(configuration.clock); - return std::make_unique(configuration); -} - ModuleRtpRtcpImpl::ModuleRtpRtcpImpl(const Configuration& configuration) : rtcp_sender_(configuration), rtcp_receiver_(configuration, this), @@ -312,7 +304,7 @@ RTCPSender::FeedbackState ModuleRtpRtcpImpl::GetFeedbackState() { state.send_bitrate = rtp_sender_->packet_sender.GetSendRates().Sum().bps(); } - state.module = this; + state.receiver = &rtcp_receiver_; LastReceivedNTP(&state.last_rr_ntp_secs, &state.last_rr_ntp_frac, &state.remote_sr); @@ -793,11 +785,6 @@ bool ModuleRtpRtcpImpl::LastReceivedNTP( return true; } -// Called from RTCPsender. -std::vector ModuleRtpRtcpImpl::BoundingSet(bool* tmmbr_owner) { - return rtcp_receiver_.BoundingSet(tmmbr_owner); -} - void ModuleRtpRtcpImpl::set_rtt_ms(int64_t rtt_ms) { { rtc::CritScope cs(&critical_section_rtt_); diff --git a/modules/rtp_rtcp/source/rtp_rtcp_impl.h b/modules/rtp_rtcp/source/rtp_rtcp_impl.h index debb433297..2d07060b52 100644 --- a/modules/rtp_rtcp/source/rtp_rtcp_impl.h +++ b/modules/rtp_rtcp/source/rtp_rtcp_impl.h @@ -42,6 +42,7 @@ class Clock; struct PacedPacketInfo; struct RTPVideoHeader; +// DEPRECATED. class ModuleRtpRtcpImpl : public RtpRtcp, public RTCPReceiver::ModuleRtpRtcp { public: explicit ModuleRtpRtcpImpl(const RtpRtcp::Configuration& configuration); @@ -257,8 +258,6 @@ class ModuleRtpRtcpImpl : public RtpRtcp, public RTCPReceiver::ModuleRtpRtcp { uint32_t* NTPfrac, uint32_t* remote_sr) const; - std::vector BoundingSet(bool* tmmbr_owner); - void BitrateSent(uint32_t* total_rate, uint32_t* video_rate, uint32_t* fec_rate, diff --git a/modules/rtp_rtcp/source/rtp_rtcp_impl2.cc b/modules/rtp_rtcp/source/rtp_rtcp_impl2.cc new file mode 100644 index 0000000000..c8f10ac481 --- /dev/null +++ b/modules/rtp_rtcp/source/rtp_rtcp_impl2.cc @@ -0,0 +1,837 @@ +/* + * Copyright (c) 2012 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_rtcp_impl2.h" + +#include + +#include +#include +#include +#include +#include +#include + +#include "api/transport/field_trial_based_config.h" +#include "modules/rtp_rtcp/source/rtcp_packet/dlrr.h" +#include "modules/rtp_rtcp/source/rtp_rtcp_config.h" +#include "rtc_base/checks.h" +#include "rtc_base/logging.h" + +#ifdef _WIN32 +// Disable warning C4355: 'this' : used in base member initializer list. +#pragma warning(disable : 4355) +#endif + +namespace webrtc { +namespace { +const int64_t kRtpRtcpMaxIdleTimeProcessMs = 5; +const int64_t kRtpRtcpRttProcessTimeMs = 1000; +const int64_t kRtpRtcpBitrateProcessTimeMs = 10; +const int64_t kDefaultExpectedRetransmissionTimeMs = 125; +} // namespace + +ModuleRtpRtcpImpl2::RtpSenderContext::RtpSenderContext( + const RtpRtcp::Configuration& config) + : packet_history(config.clock, config.enable_rtx_padding_prioritization), + packet_sender(config, &packet_history), + non_paced_sender(&packet_sender), + packet_generator( + config, + &packet_history, + config.paced_sender ? config.paced_sender : &non_paced_sender) {} + +std::unique_ptr RtpRtcp::Create(const Configuration& configuration) { + RTC_DCHECK(configuration.clock); + return std::make_unique(configuration); +} + +ModuleRtpRtcpImpl2::ModuleRtpRtcpImpl2(const Configuration& configuration) + : rtcp_sender_(configuration), + rtcp_receiver_(configuration, this), + clock_(configuration.clock), + last_bitrate_process_time_(clock_->TimeInMilliseconds()), + last_rtt_process_time_(clock_->TimeInMilliseconds()), + next_process_time_(clock_->TimeInMilliseconds() + + kRtpRtcpMaxIdleTimeProcessMs), + packet_overhead_(28), // IPV4 UDP. + nack_last_time_sent_full_ms_(0), + nack_last_seq_number_sent_(0), + remote_bitrate_(configuration.remote_bitrate_estimator), + rtt_stats_(configuration.rtt_stats), + rtt_ms_(0) { + process_thread_checker_.Detach(); + if (!configuration.receiver_only) { + rtp_sender_ = std::make_unique(configuration); + // Make sure rtcp sender use same timestamp offset as rtp sender. + rtcp_sender_.SetTimestampOffset( + rtp_sender_->packet_generator.TimestampOffset()); + } + + // Set default packet size limit. + // TODO(nisse): Kind-of duplicates + // webrtc::VideoSendStream::Config::Rtp::kDefaultMaxPacketSize. + const size_t kTcpOverIpv4HeaderSize = 40; + SetMaxRtpPacketSize(IP_PACKET_SIZE - kTcpOverIpv4HeaderSize); +} + +ModuleRtpRtcpImpl2::~ModuleRtpRtcpImpl2() { + RTC_DCHECK_RUN_ON(&construction_thread_checker_); +} + +// Returns the number of milliseconds until the module want a worker thread +// to call Process. +int64_t ModuleRtpRtcpImpl2::TimeUntilNextProcess() { + RTC_DCHECK_RUN_ON(&process_thread_checker_); + return std::max(0, + next_process_time_ - clock_->TimeInMilliseconds()); +} + +// Process any pending tasks such as timeouts (non time critical events). +void ModuleRtpRtcpImpl2::Process() { + RTC_DCHECK_RUN_ON(&process_thread_checker_); + const int64_t now = clock_->TimeInMilliseconds(); + // TODO(bugs.webrtc.org/11581): Figure out why we need to call Process() 200 + // times a second. + next_process_time_ = now + kRtpRtcpMaxIdleTimeProcessMs; + + if (rtp_sender_) { + if (now >= last_bitrate_process_time_ + kRtpRtcpBitrateProcessTimeMs) { + rtp_sender_->packet_sender.ProcessBitrateAndNotifyObservers(); + last_bitrate_process_time_ = now; + // TODO(bugs.webrtc.org/11581): Is this a bug? At the top of the function, + // next_process_time_ is incremented by 5ms, here we effectively do a + // std::min() of (now + 5ms, now + 10ms). Seems like this is a no-op? + next_process_time_ = + std::min(next_process_time_, now + kRtpRtcpBitrateProcessTimeMs); + } + } + + // TODO(bugs.webrtc.org/11581): We update the RTT once a second, whereas other + // things that run in this method are updated much more frequently. Move the + // RTT checking over to the worker thread, which matches better with where the + // stats are maintained. + bool process_rtt = now >= last_rtt_process_time_ + kRtpRtcpRttProcessTimeMs; + if (rtcp_sender_.Sending()) { + // Process RTT if we have received a report block and we haven't + // processed RTT for at least |kRtpRtcpRttProcessTimeMs| milliseconds. + // Note that LastReceivedReportBlockMs() grabs a lock, so check + // |process_rtt| first. + if (process_rtt && + rtcp_receiver_.LastReceivedReportBlockMs() > last_rtt_process_time_) { + std::vector receive_blocks; + rtcp_receiver_.StatisticsReceived(&receive_blocks); + int64_t max_rtt = 0; + for (std::vector::iterator it = receive_blocks.begin(); + it != receive_blocks.end(); ++it) { + int64_t rtt = 0; + rtcp_receiver_.RTT(it->sender_ssrc, &rtt, NULL, NULL, NULL); + max_rtt = (rtt > max_rtt) ? rtt : max_rtt; + } + // Report the rtt. + if (rtt_stats_ && max_rtt != 0) + rtt_stats_->OnRttUpdate(max_rtt); + } + + // Verify receiver reports are delivered and the reported sequence number + // is increasing. + // TODO(bugs.webrtc.org/11581): The timeout value needs to be checked every + // few seconds (see internals of RtcpRrTimeout). Here, we may be polling it + // a couple of hundred times a second, which isn't great since it grabs a + // lock. Note also that LastReceivedReportBlockMs() (called above) and + // RtcpRrTimeout() both grab the same lock and check the same timer, so + // it should be possible to consolidate that work somehow. + if (rtcp_receiver_.RtcpRrTimeout()) { + RTC_LOG_F(LS_WARNING) << "Timeout: No RTCP RR received."; + } else if (rtcp_receiver_.RtcpRrSequenceNumberTimeout()) { + RTC_LOG_F(LS_WARNING) << "Timeout: No increase in RTCP RR extended " + "highest sequence number."; + } + + if (remote_bitrate_ && rtcp_sender_.TMMBR()) { + unsigned int target_bitrate = 0; + std::vector ssrcs; + if (remote_bitrate_->LatestEstimate(&ssrcs, &target_bitrate)) { + if (!ssrcs.empty()) { + target_bitrate = target_bitrate / ssrcs.size(); + } + rtcp_sender_.SetTargetBitrate(target_bitrate); + } + } + } else { + // Report rtt from receiver. + if (process_rtt) { + int64_t rtt_ms; + if (rtt_stats_ && rtcp_receiver_.GetAndResetXrRrRtt(&rtt_ms)) { + rtt_stats_->OnRttUpdate(rtt_ms); + } + } + } + + // Get processed rtt. + if (process_rtt) { + last_rtt_process_time_ = now; + // TODO(bugs.webrtc.org/11581): Is this a bug? At the top of the function, + // next_process_time_ is incremented by 5ms, here we effectively do a + // std::min() of (now + 5ms, now + 1000ms). Seems like this is a no-op? + next_process_time_ = std::min( + next_process_time_, last_rtt_process_time_ + kRtpRtcpRttProcessTimeMs); + if (rtt_stats_) { + // Make sure we have a valid RTT before setting. + int64_t last_rtt = rtt_stats_->LastProcessedRtt(); + if (last_rtt >= 0) + set_rtt_ms(last_rtt); + } + } + + if (rtcp_sender_.TimeToSendRTCPReport()) + rtcp_sender_.SendRTCP(GetFeedbackState(), kRtcpReport); + + if (TMMBR() && rtcp_receiver_.UpdateTmmbrTimers()) { + rtcp_receiver_.NotifyTmmbrUpdated(); + } +} + +void ModuleRtpRtcpImpl2::SetRtxSendStatus(int mode) { + rtp_sender_->packet_generator.SetRtxStatus(mode); +} + +int ModuleRtpRtcpImpl2::RtxSendStatus() const { + return rtp_sender_ ? rtp_sender_->packet_generator.RtxStatus() : kRtxOff; +} + +void ModuleRtpRtcpImpl2::SetRtxSendPayloadType(int payload_type, + int associated_payload_type) { + rtp_sender_->packet_generator.SetRtxPayloadType(payload_type, + associated_payload_type); +} + +absl::optional ModuleRtpRtcpImpl2::RtxSsrc() const { + return rtp_sender_ ? rtp_sender_->packet_generator.RtxSsrc() : absl::nullopt; +} + +absl::optional ModuleRtpRtcpImpl2::FlexfecSsrc() const { + if (rtp_sender_) { + return rtp_sender_->packet_generator.FlexfecSsrc(); + } + return absl::nullopt; +} + +void ModuleRtpRtcpImpl2::IncomingRtcpPacket(const uint8_t* rtcp_packet, + const size_t length) { + rtcp_receiver_.IncomingPacket(rtcp_packet, length); +} + +void ModuleRtpRtcpImpl2::RegisterSendPayloadFrequency(int payload_type, + int payload_frequency) { + rtcp_sender_.SetRtpClockRate(payload_type, payload_frequency); +} + +int32_t ModuleRtpRtcpImpl2::DeRegisterSendPayload(const int8_t payload_type) { + return 0; +} + +uint32_t ModuleRtpRtcpImpl2::StartTimestamp() const { + return rtp_sender_->packet_generator.TimestampOffset(); +} + +// Configure start timestamp, default is a random number. +void ModuleRtpRtcpImpl2::SetStartTimestamp(const uint32_t timestamp) { + rtcp_sender_.SetTimestampOffset(timestamp); + rtp_sender_->packet_generator.SetTimestampOffset(timestamp); + rtp_sender_->packet_sender.SetTimestampOffset(timestamp); +} + +uint16_t ModuleRtpRtcpImpl2::SequenceNumber() const { + return rtp_sender_->packet_generator.SequenceNumber(); +} + +// Set SequenceNumber, default is a random number. +void ModuleRtpRtcpImpl2::SetSequenceNumber(const uint16_t seq_num) { + rtp_sender_->packet_generator.SetSequenceNumber(seq_num); +} + +void ModuleRtpRtcpImpl2::SetRtpState(const RtpState& rtp_state) { + rtp_sender_->packet_generator.SetRtpState(rtp_state); + rtp_sender_->packet_sender.SetMediaHasBeenSent(rtp_state.media_has_been_sent); + rtcp_sender_.SetTimestampOffset(rtp_state.start_timestamp); +} + +void ModuleRtpRtcpImpl2::SetRtxState(const RtpState& rtp_state) { + rtp_sender_->packet_generator.SetRtxRtpState(rtp_state); +} + +RtpState ModuleRtpRtcpImpl2::GetRtpState() const { + RtpState state = rtp_sender_->packet_generator.GetRtpState(); + state.media_has_been_sent = rtp_sender_->packet_sender.MediaHasBeenSent(); + return state; +} + +RtpState ModuleRtpRtcpImpl2::GetRtxState() const { + return rtp_sender_->packet_generator.GetRtxRtpState(); +} + +void ModuleRtpRtcpImpl2::SetRid(const std::string& rid) { + if (rtp_sender_) { + rtp_sender_->packet_generator.SetRid(rid); + } +} + +void ModuleRtpRtcpImpl2::SetMid(const std::string& mid) { + if (rtp_sender_) { + rtp_sender_->packet_generator.SetMid(mid); + } + // TODO(bugs.webrtc.org/4050): If we end up supporting the MID SDES item for + // RTCP, this will need to be passed down to the RTCPSender also. +} + +void ModuleRtpRtcpImpl2::SetCsrcs(const std::vector& csrcs) { + rtcp_sender_.SetCsrcs(csrcs); + rtp_sender_->packet_generator.SetCsrcs(csrcs); +} + +// TODO(pbos): Handle media and RTX streams separately (separate RTCP +// feedbacks). +RTCPSender::FeedbackState ModuleRtpRtcpImpl2::GetFeedbackState() { + RTCPSender::FeedbackState state; + // This is called also when receiver_only is true. Hence below + // checks that rtp_sender_ exists. + if (rtp_sender_) { + StreamDataCounters rtp_stats; + StreamDataCounters rtx_stats; + rtp_sender_->packet_sender.GetDataCounters(&rtp_stats, &rtx_stats); + state.packets_sent = + rtp_stats.transmitted.packets + rtx_stats.transmitted.packets; + state.media_bytes_sent = rtp_stats.transmitted.payload_bytes + + rtx_stats.transmitted.payload_bytes; + state.send_bitrate = + rtp_sender_->packet_sender.GetSendRates().Sum().bps(); + } + state.receiver = &rtcp_receiver_; + + LastReceivedNTP(&state.last_rr_ntp_secs, &state.last_rr_ntp_frac, + &state.remote_sr); + + state.last_xr_rtis = rtcp_receiver_.ConsumeReceivedXrReferenceTimeInfo(); + + return state; +} + +// TODO(nisse): This method shouldn't be called for a receive-only +// stream. Delete rtp_sender_ check as soon as all applications are +// updated. +int32_t ModuleRtpRtcpImpl2::SetSendingStatus(const bool sending) { + if (rtcp_sender_.Sending() != sending) { + // Sends RTCP BYE when going from true to false + if (rtcp_sender_.SetSendingStatus(GetFeedbackState(), sending) != 0) { + RTC_LOG(LS_WARNING) << "Failed to send RTCP BYE"; + } + } + return 0; +} + +bool ModuleRtpRtcpImpl2::Sending() const { + return rtcp_sender_.Sending(); +} + +// TODO(nisse): This method shouldn't be called for a receive-only +// stream. Delete rtp_sender_ check as soon as all applications are +// updated. +void ModuleRtpRtcpImpl2::SetSendingMediaStatus(const bool sending) { + if (rtp_sender_) { + rtp_sender_->packet_generator.SetSendingMediaStatus(sending); + } else { + RTC_DCHECK(!sending); + } +} + +bool ModuleRtpRtcpImpl2::SendingMedia() const { + return rtp_sender_ ? rtp_sender_->packet_generator.SendingMedia() : false; +} + +bool ModuleRtpRtcpImpl2::IsAudioConfigured() const { + return rtp_sender_ ? rtp_sender_->packet_generator.IsAudioConfigured() + : false; +} + +void ModuleRtpRtcpImpl2::SetAsPartOfAllocation(bool part_of_allocation) { + RTC_CHECK(rtp_sender_); + rtp_sender_->packet_sender.ForceIncludeSendPacketsInAllocation( + part_of_allocation); +} + +bool ModuleRtpRtcpImpl2::OnSendingRtpFrame(uint32_t timestamp, + int64_t capture_time_ms, + int payload_type, + bool force_sender_report) { + if (!Sending()) + return false; + + rtcp_sender_.SetLastRtpTime(timestamp, capture_time_ms, payload_type); + // Make sure an RTCP report isn't queued behind a key frame. + if (rtcp_sender_.TimeToSendRTCPReport(force_sender_report)) + rtcp_sender_.SendRTCP(GetFeedbackState(), kRtcpReport); + + return true; +} + +bool ModuleRtpRtcpImpl2::TrySendPacket(RtpPacketToSend* packet, + const PacedPacketInfo& pacing_info) { + RTC_DCHECK(rtp_sender_); + // TODO(sprang): Consider if we can remove this check. + if (!rtp_sender_->packet_generator.SendingMedia()) { + return false; + } + rtp_sender_->packet_sender.SendPacket(packet, pacing_info); + return true; +} + +void ModuleRtpRtcpImpl2::OnPacketsAcknowledged( + rtc::ArrayView sequence_numbers) { + RTC_DCHECK(rtp_sender_); + rtp_sender_->packet_history.CullAcknowledgedPackets(sequence_numbers); +} + +bool ModuleRtpRtcpImpl2::SupportsPadding() const { + RTC_DCHECK(rtp_sender_); + return rtp_sender_->packet_generator.SupportsPadding(); +} + +bool ModuleRtpRtcpImpl2::SupportsRtxPayloadPadding() const { + RTC_DCHECK(rtp_sender_); + return rtp_sender_->packet_generator.SupportsRtxPayloadPadding(); +} + +std::vector> +ModuleRtpRtcpImpl2::GeneratePadding(size_t target_size_bytes) { + RTC_DCHECK(rtp_sender_); + return rtp_sender_->packet_generator.GeneratePadding( + target_size_bytes, rtp_sender_->packet_sender.MediaHasBeenSent()); +} + +std::vector +ModuleRtpRtcpImpl2::GetSentRtpPacketInfos( + rtc::ArrayView sequence_numbers) const { + RTC_DCHECK(rtp_sender_); + return rtp_sender_->packet_sender.GetSentRtpPacketInfos(sequence_numbers); +} + +size_t ModuleRtpRtcpImpl2::ExpectedPerPacketOverhead() const { + if (!rtp_sender_) { + return 0; + } + return rtp_sender_->packet_generator.ExpectedPerPacketOverhead(); +} + +size_t ModuleRtpRtcpImpl2::MaxRtpPacketSize() const { + RTC_DCHECK(rtp_sender_); + return rtp_sender_->packet_generator.MaxRtpPacketSize(); +} + +void ModuleRtpRtcpImpl2::SetMaxRtpPacketSize(size_t rtp_packet_size) { + RTC_DCHECK_LE(rtp_packet_size, IP_PACKET_SIZE) + << "rtp packet size too large: " << rtp_packet_size; + RTC_DCHECK_GT(rtp_packet_size, packet_overhead_) + << "rtp packet size too small: " << rtp_packet_size; + + rtcp_sender_.SetMaxRtpPacketSize(rtp_packet_size); + if (rtp_sender_) { + rtp_sender_->packet_generator.SetMaxRtpPacketSize(rtp_packet_size); + } +} + +RtcpMode ModuleRtpRtcpImpl2::RTCP() const { + return rtcp_sender_.Status(); +} + +// Configure RTCP status i.e on/off. +void ModuleRtpRtcpImpl2::SetRTCPStatus(const RtcpMode method) { + rtcp_sender_.SetRTCPStatus(method); +} + +int32_t ModuleRtpRtcpImpl2::SetCNAME(const char* c_name) { + return rtcp_sender_.SetCNAME(c_name); +} + +int32_t ModuleRtpRtcpImpl2::AddMixedCNAME(uint32_t ssrc, const char* c_name) { + return rtcp_sender_.AddMixedCNAME(ssrc, c_name); +} + +int32_t ModuleRtpRtcpImpl2::RemoveMixedCNAME(const uint32_t ssrc) { + return rtcp_sender_.RemoveMixedCNAME(ssrc); +} + +int32_t ModuleRtpRtcpImpl2::RemoteCNAME(const uint32_t remote_ssrc, + char c_name[RTCP_CNAME_SIZE]) const { + return rtcp_receiver_.CNAME(remote_ssrc, c_name); +} + +int32_t ModuleRtpRtcpImpl2::RemoteNTP(uint32_t* received_ntpsecs, + uint32_t* received_ntpfrac, + uint32_t* rtcp_arrival_time_secs, + uint32_t* rtcp_arrival_time_frac, + uint32_t* rtcp_timestamp) const { + return rtcp_receiver_.NTP(received_ntpsecs, received_ntpfrac, + rtcp_arrival_time_secs, rtcp_arrival_time_frac, + rtcp_timestamp) + ? 0 + : -1; +} + +// Get RoundTripTime. +int32_t ModuleRtpRtcpImpl2::RTT(const uint32_t remote_ssrc, + int64_t* rtt, + int64_t* avg_rtt, + int64_t* min_rtt, + int64_t* max_rtt) const { + int32_t ret = rtcp_receiver_.RTT(remote_ssrc, rtt, avg_rtt, min_rtt, max_rtt); + if (rtt && *rtt == 0) { + // Try to get RTT from RtcpRttStats class. + *rtt = rtt_ms(); + } + return ret; +} + +int64_t ModuleRtpRtcpImpl2::ExpectedRetransmissionTimeMs() const { + int64_t expected_retransmission_time_ms = rtt_ms(); + if (expected_retransmission_time_ms > 0) { + return expected_retransmission_time_ms; + } + // No rtt available (|kRtpRtcpRttProcessTimeMs| not yet passed?), so try to + // poll avg_rtt_ms directly from rtcp receiver. + if (rtcp_receiver_.RTT(rtcp_receiver_.RemoteSSRC(), nullptr, + &expected_retransmission_time_ms, nullptr, + nullptr) == 0) { + return expected_retransmission_time_ms; + } + return kDefaultExpectedRetransmissionTimeMs; +} + +// Force a send of an RTCP packet. +// Normal SR and RR are triggered via the process function. +int32_t ModuleRtpRtcpImpl2::SendRTCP(RTCPPacketType packet_type) { + return rtcp_sender_.SendRTCP(GetFeedbackState(), packet_type); +} + +int32_t ModuleRtpRtcpImpl2::SetRTCPApplicationSpecificData( + const uint8_t sub_type, + const uint32_t name, + const uint8_t* data, + const uint16_t length) { + return rtcp_sender_.SetApplicationSpecificData(sub_type, name, data, length); +} + +void ModuleRtpRtcpImpl2::SetRtcpXrRrtrStatus(bool enable) { + rtcp_receiver_.SetRtcpXrRrtrStatus(enable); + rtcp_sender_.SendRtcpXrReceiverReferenceTime(enable); +} + +bool ModuleRtpRtcpImpl2::RtcpXrRrtrStatus() const { + return rtcp_sender_.RtcpXrReceiverReferenceTime(); +} + +// TODO(asapersson): Replace this method with the one below. +int32_t ModuleRtpRtcpImpl2::DataCountersRTP(size_t* bytes_sent, + uint32_t* packets_sent) const { + StreamDataCounters rtp_stats; + StreamDataCounters rtx_stats; + rtp_sender_->packet_sender.GetDataCounters(&rtp_stats, &rtx_stats); + + if (bytes_sent) { + // TODO(http://crbug.com/webrtc/10525): Bytes sent should only include + // payload bytes, not header and padding bytes. + *bytes_sent = rtp_stats.transmitted.payload_bytes + + rtp_stats.transmitted.padding_bytes + + rtp_stats.transmitted.header_bytes + + rtx_stats.transmitted.payload_bytes + + rtx_stats.transmitted.padding_bytes + + rtx_stats.transmitted.header_bytes; + } + if (packets_sent) { + *packets_sent = + rtp_stats.transmitted.packets + rtx_stats.transmitted.packets; + } + return 0; +} + +void ModuleRtpRtcpImpl2::GetSendStreamDataCounters( + StreamDataCounters* rtp_counters, + StreamDataCounters* rtx_counters) const { + rtp_sender_->packet_sender.GetDataCounters(rtp_counters, rtx_counters); +} + +// Received RTCP report. +int32_t ModuleRtpRtcpImpl2::RemoteRTCPStat( + std::vector* receive_blocks) const { + return rtcp_receiver_.StatisticsReceived(receive_blocks); +} + +std::vector ModuleRtpRtcpImpl2::GetLatestReportBlockData() + const { + return rtcp_receiver_.GetLatestReportBlockData(); +} + +// (REMB) Receiver Estimated Max Bitrate. +void ModuleRtpRtcpImpl2::SetRemb(int64_t bitrate_bps, + std::vector ssrcs) { + rtcp_sender_.SetRemb(bitrate_bps, std::move(ssrcs)); +} + +void ModuleRtpRtcpImpl2::UnsetRemb() { + rtcp_sender_.UnsetRemb(); +} + +void ModuleRtpRtcpImpl2::SetExtmapAllowMixed(bool extmap_allow_mixed) { + rtp_sender_->packet_generator.SetExtmapAllowMixed(extmap_allow_mixed); +} + +int32_t ModuleRtpRtcpImpl2::RegisterSendRtpHeaderExtension( + const RTPExtensionType type, + const uint8_t id) { + return rtp_sender_->packet_generator.RegisterRtpHeaderExtension(type, id); +} + +void ModuleRtpRtcpImpl2::RegisterRtpHeaderExtension(absl::string_view uri, + int id) { + bool registered = + rtp_sender_->packet_generator.RegisterRtpHeaderExtension(uri, id); + RTC_CHECK(registered); +} + +int32_t ModuleRtpRtcpImpl2::DeregisterSendRtpHeaderExtension( + const RTPExtensionType type) { + return rtp_sender_->packet_generator.DeregisterRtpHeaderExtension(type); +} +void ModuleRtpRtcpImpl2::DeregisterSendRtpHeaderExtension( + absl::string_view uri) { + rtp_sender_->packet_generator.DeregisterRtpHeaderExtension(uri); +} + +// (TMMBR) Temporary Max Media Bit Rate. +bool ModuleRtpRtcpImpl2::TMMBR() const { + return rtcp_sender_.TMMBR(); +} + +void ModuleRtpRtcpImpl2::SetTMMBRStatus(const bool enable) { + rtcp_sender_.SetTMMBRStatus(enable); +} + +void ModuleRtpRtcpImpl2::SetTmmbn(std::vector bounding_set) { + rtcp_sender_.SetTmmbn(std::move(bounding_set)); +} + +// Send a Negative acknowledgment packet. +int32_t ModuleRtpRtcpImpl2::SendNACK(const uint16_t* nack_list, + const uint16_t size) { + uint16_t nack_length = size; + uint16_t start_id = 0; + int64_t now_ms = clock_->TimeInMilliseconds(); + if (TimeToSendFullNackList(now_ms)) { + nack_last_time_sent_full_ms_ = now_ms; + } else { + // Only send extended list. + if (nack_last_seq_number_sent_ == nack_list[size - 1]) { + // Last sequence number is the same, do not send list. + return 0; + } + // Send new sequence numbers. + for (int i = 0; i < size; ++i) { + if (nack_last_seq_number_sent_ == nack_list[i]) { + start_id = i + 1; + break; + } + } + nack_length = size - start_id; + } + + // Our RTCP NACK implementation is limited to kRtcpMaxNackFields sequence + // numbers per RTCP packet. + if (nack_length > kRtcpMaxNackFields) { + nack_length = kRtcpMaxNackFields; + } + nack_last_seq_number_sent_ = nack_list[start_id + nack_length - 1]; + + return rtcp_sender_.SendRTCP(GetFeedbackState(), kRtcpNack, nack_length, + &nack_list[start_id]); +} + +void ModuleRtpRtcpImpl2::SendNack( + const std::vector& sequence_numbers) { + rtcp_sender_.SendRTCP(GetFeedbackState(), kRtcpNack, sequence_numbers.size(), + sequence_numbers.data()); +} + +bool ModuleRtpRtcpImpl2::TimeToSendFullNackList(int64_t now) const { + // Use RTT from RtcpRttStats class if provided. + int64_t rtt = rtt_ms(); + if (rtt == 0) { + rtcp_receiver_.RTT(rtcp_receiver_.RemoteSSRC(), NULL, &rtt, NULL, NULL); + } + + const int64_t kStartUpRttMs = 100; + int64_t wait_time = 5 + ((rtt * 3) >> 1); // 5 + RTT * 1.5. + if (rtt == 0) { + wait_time = kStartUpRttMs; + } + + // Send a full NACK list once within every |wait_time|. + return now - nack_last_time_sent_full_ms_ > wait_time; +} + +// Store the sent packets, needed to answer to Negative acknowledgment requests. +void ModuleRtpRtcpImpl2::SetStorePacketsStatus(const bool enable, + const uint16_t number_to_store) { + rtp_sender_->packet_history.SetStorePacketsStatus( + enable ? RtpPacketHistory::StorageMode::kStoreAndCull + : RtpPacketHistory::StorageMode::kDisabled, + number_to_store); +} + +bool ModuleRtpRtcpImpl2::StorePackets() const { + return rtp_sender_->packet_history.GetStorageMode() != + RtpPacketHistory::StorageMode::kDisabled; +} + +void ModuleRtpRtcpImpl2::SendCombinedRtcpPacket( + std::vector> rtcp_packets) { + rtcp_sender_.SendCombinedRtcpPacket(std::move(rtcp_packets)); +} + +int32_t ModuleRtpRtcpImpl2::SendLossNotification(uint16_t last_decoded_seq_num, + uint16_t last_received_seq_num, + bool decodability_flag, + bool buffering_allowed) { + return rtcp_sender_.SendLossNotification( + GetFeedbackState(), last_decoded_seq_num, last_received_seq_num, + decodability_flag, buffering_allowed); +} + +void ModuleRtpRtcpImpl2::SetRemoteSSRC(const uint32_t ssrc) { + // Inform about the incoming SSRC. + rtcp_sender_.SetRemoteSSRC(ssrc); + rtcp_receiver_.SetRemoteSSRC(ssrc); +} + +// TODO(nisse): Delete video_rate amd fec_rate arguments. +void ModuleRtpRtcpImpl2::BitrateSent(uint32_t* total_rate, + uint32_t* video_rate, + uint32_t* fec_rate, + uint32_t* nack_rate) const { + RtpSendRates send_rates = rtp_sender_->packet_sender.GetSendRates(); + *total_rate = send_rates.Sum().bps(); + if (video_rate) + *video_rate = 0; + if (fec_rate) + *fec_rate = 0; + *nack_rate = send_rates[RtpPacketMediaType::kRetransmission].bps(); +} + +RtpSendRates ModuleRtpRtcpImpl2::GetSendRates() const { + return rtp_sender_->packet_sender.GetSendRates(); +} + +void ModuleRtpRtcpImpl2::OnRequestSendReport() { + SendRTCP(kRtcpSr); +} + +void ModuleRtpRtcpImpl2::OnReceivedNack( + const std::vector& nack_sequence_numbers) { + if (!rtp_sender_) + return; + + if (!StorePackets() || nack_sequence_numbers.empty()) { + return; + } + // Use RTT from RtcpRttStats class if provided. + int64_t rtt = rtt_ms(); + if (rtt == 0) { + rtcp_receiver_.RTT(rtcp_receiver_.RemoteSSRC(), NULL, &rtt, NULL, NULL); + } + rtp_sender_->packet_generator.OnReceivedNack(nack_sequence_numbers, rtt); +} + +void ModuleRtpRtcpImpl2::OnReceivedRtcpReportBlocks( + const ReportBlockList& report_blocks) { + if (rtp_sender_) { + uint32_t ssrc = SSRC(); + absl::optional rtx_ssrc; + if (rtp_sender_->packet_generator.RtxStatus() != kRtxOff) { + rtx_ssrc = rtp_sender_->packet_generator.RtxSsrc(); + } + + for (const RTCPReportBlock& report_block : report_blocks) { + if (ssrc == report_block.source_ssrc) { + rtp_sender_->packet_generator.OnReceivedAckOnSsrc( + report_block.extended_highest_sequence_number); + } else if (rtx_ssrc && *rtx_ssrc == report_block.source_ssrc) { + rtp_sender_->packet_generator.OnReceivedAckOnRtxSsrc( + report_block.extended_highest_sequence_number); + } + } + } +} + +bool ModuleRtpRtcpImpl2::LastReceivedNTP( + uint32_t* rtcp_arrival_time_secs, // When we got the last report. + uint32_t* rtcp_arrival_time_frac, + uint32_t* remote_sr) const { + // Remote SR: NTP inside the last received (mid 16 bits from sec and frac). + uint32_t ntp_secs = 0; + uint32_t ntp_frac = 0; + + if (!rtcp_receiver_.NTP(&ntp_secs, &ntp_frac, rtcp_arrival_time_secs, + rtcp_arrival_time_frac, NULL)) { + return false; + } + *remote_sr = + ((ntp_secs & 0x0000ffff) << 16) + ((ntp_frac & 0xffff0000) >> 16); + return true; +} + +void ModuleRtpRtcpImpl2::set_rtt_ms(int64_t rtt_ms) { + { + rtc::CritScope cs(&critical_section_rtt_); + rtt_ms_ = rtt_ms; + } + if (rtp_sender_) { + rtp_sender_->packet_history.SetRtt(rtt_ms); + } +} + +int64_t ModuleRtpRtcpImpl2::rtt_ms() const { + rtc::CritScope cs(&critical_section_rtt_); + return rtt_ms_; +} + +void ModuleRtpRtcpImpl2::SetVideoBitrateAllocation( + const VideoBitrateAllocation& bitrate) { + rtcp_sender_.SetVideoBitrateAllocation(bitrate); +} + +RTPSender* ModuleRtpRtcpImpl2::RtpSender() { + return rtp_sender_ ? &rtp_sender_->packet_generator : nullptr; +} + +const RTPSender* ModuleRtpRtcpImpl2::RtpSender() const { + return rtp_sender_ ? &rtp_sender_->packet_generator : nullptr; +} + +DataRate ModuleRtpRtcpImpl2::SendRate() const { + RTC_DCHECK(rtp_sender_); + return rtp_sender_->packet_sender.GetSendRates().Sum(); +} + +DataRate ModuleRtpRtcpImpl2::NackOverheadRate() const { + RTC_DCHECK(rtp_sender_); + return rtp_sender_->packet_sender + .GetSendRates()[RtpPacketMediaType::kRetransmission]; +} + +} // namespace webrtc diff --git a/modules/rtp_rtcp/source/rtp_rtcp_impl2.h b/modules/rtp_rtcp/source/rtp_rtcp_impl2.h new file mode 100644 index 0000000000..67409c059f --- /dev/null +++ b/modules/rtp_rtcp/source/rtp_rtcp_impl2.h @@ -0,0 +1,355 @@ +/* + * Copyright (c) 2012 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_RTCP_IMPL2_H_ +#define MODULES_RTP_RTCP_SOURCE_RTP_RTCP_IMPL2_H_ + +#include +#include + +#include +#include +#include +#include + +#include "absl/types/optional.h" +#include "api/rtp_headers.h" +#include "api/video/video_bitrate_allocation.h" +#include "modules/include/module_fec_types.h" +#include "modules/remote_bitrate_estimator/include/remote_bitrate_estimator.h" +#include "modules/rtp_rtcp/include/rtp_rtcp.h" +#include "modules/rtp_rtcp/include/rtp_rtcp_defines.h" // RTCPPacketType +#include "modules/rtp_rtcp/source/rtcp_packet/tmmb_item.h" +#include "modules/rtp_rtcp/source/rtcp_receiver.h" +#include "modules/rtp_rtcp/source/rtcp_sender.h" +#include "modules/rtp_rtcp/source/rtp_packet_history.h" +#include "modules/rtp_rtcp/source/rtp_packet_to_send.h" +#include "modules/rtp_rtcp/source/rtp_sender.h" +#include "modules/rtp_rtcp/source/rtp_sender_egress.h" +#include "rtc_base/critical_section.h" +#include "rtc_base/gtest_prod_util.h" +#include "rtc_base/synchronization/sequence_checker.h" + +namespace webrtc { + +class Clock; +struct PacedPacketInfo; +struct RTPVideoHeader; + +class ModuleRtpRtcpImpl2 final : public RtpRtcp, + public RTCPReceiver::ModuleRtpRtcp { + public: + explicit ModuleRtpRtcpImpl2(const RtpRtcp::Configuration& configuration); + ~ModuleRtpRtcpImpl2() override; + + // Returns the number of milliseconds until the module want a worker thread to + // call Process. + int64_t TimeUntilNextProcess() override; + + // Process any pending tasks such as timeouts. + void Process() override; + + // Receiver part. + + // Called when we receive an RTCP packet. + void IncomingRtcpPacket(const uint8_t* incoming_packet, + size_t incoming_packet_length) override; + + void SetRemoteSSRC(uint32_t ssrc) override; + + // Sender part. + void RegisterSendPayloadFrequency(int payload_type, + int payload_frequency) override; + + int32_t DeRegisterSendPayload(int8_t payload_type) override; + + void SetExtmapAllowMixed(bool extmap_allow_mixed) override; + + // Register RTP header extension. + int32_t RegisterSendRtpHeaderExtension(RTPExtensionType type, + uint8_t id) override; + void RegisterRtpHeaderExtension(absl::string_view uri, int id) override; + int32_t DeregisterSendRtpHeaderExtension(RTPExtensionType type) override; + void DeregisterSendRtpHeaderExtension(absl::string_view uri) override; + + bool SupportsPadding() const override; + bool SupportsRtxPayloadPadding() const override; + + // Get start timestamp. + uint32_t StartTimestamp() const override; + + // Configure start timestamp, default is a random number. + void SetStartTimestamp(uint32_t timestamp) override; + + uint16_t SequenceNumber() const override; + + // Set SequenceNumber, default is a random number. + void SetSequenceNumber(uint16_t seq) override; + + void SetRtpState(const RtpState& rtp_state) override; + void SetRtxState(const RtpState& rtp_state) override; + RtpState GetRtpState() const override; + RtpState GetRtxState() const override; + + uint32_t SSRC() const override { return rtcp_sender_.SSRC(); } + + void SetRid(const std::string& rid) override; + + void SetMid(const std::string& mid) override; + + void SetCsrcs(const std::vector& csrcs) override; + + RTCPSender::FeedbackState GetFeedbackState(); + + void SetRtxSendStatus(int mode) override; + int RtxSendStatus() const override; + absl::optional RtxSsrc() const override; + + void SetRtxSendPayloadType(int payload_type, + int associated_payload_type) override; + + absl::optional FlexfecSsrc() const override; + + // Sends kRtcpByeCode when going from true to false. + int32_t SetSendingStatus(bool sending) override; + + bool Sending() const override; + + // Drops or relays media packets. + void SetSendingMediaStatus(bool sending) override; + + bool SendingMedia() const override; + + bool IsAudioConfigured() const override; + + void SetAsPartOfAllocation(bool part_of_allocation) override; + + bool OnSendingRtpFrame(uint32_t timestamp, + int64_t capture_time_ms, + int payload_type, + bool force_sender_report) override; + + bool TrySendPacket(RtpPacketToSend* packet, + const PacedPacketInfo& pacing_info) override; + + void OnPacketsAcknowledged( + rtc::ArrayView sequence_numbers) override; + + std::vector> GeneratePadding( + size_t target_size_bytes) override; + + std::vector GetSentRtpPacketInfos( + rtc::ArrayView sequence_numbers) const override; + + size_t ExpectedPerPacketOverhead() const override; + + // RTCP part. + + // Get RTCP status. + RtcpMode RTCP() const override; + + // Configure RTCP status i.e on/off. + void SetRTCPStatus(RtcpMode method) override; + + // Set RTCP CName. + int32_t SetCNAME(const char* c_name) override; + + // Get remote CName. + int32_t RemoteCNAME(uint32_t remote_ssrc, + char c_name[RTCP_CNAME_SIZE]) const override; + + // Get remote NTP. + int32_t RemoteNTP(uint32_t* received_ntp_secs, + uint32_t* received_ntp_frac, + uint32_t* rtcp_arrival_time_secs, + uint32_t* rtcp_arrival_time_frac, + uint32_t* rtcp_timestamp) const override; + + int32_t AddMixedCNAME(uint32_t ssrc, const char* c_name) override; + + int32_t RemoveMixedCNAME(uint32_t ssrc) override; + + // Get RoundTripTime. + int32_t RTT(uint32_t remote_ssrc, + int64_t* rtt, + int64_t* avg_rtt, + int64_t* min_rtt, + int64_t* max_rtt) const override; + + int64_t ExpectedRetransmissionTimeMs() const override; + + // Force a send of an RTCP packet. + // Normal SR and RR are triggered via the process function. + int32_t SendRTCP(RTCPPacketType rtcpPacketType) override; + + // Statistics of the amount of data sent and received. + int32_t DataCountersRTP(size_t* bytes_sent, + uint32_t* packets_sent) const override; + + void GetSendStreamDataCounters( + StreamDataCounters* rtp_counters, + StreamDataCounters* rtx_counters) const override; + + // Get received RTCP report, report block. + int32_t RemoteRTCPStat( + std::vector* receive_blocks) const override; + // A snapshot of the most recent Report Block with additional data of + // interest to statistics. Used to implement RTCRemoteInboundRtpStreamStats. + // Within this list, the ReportBlockData::RTCPReportBlock::source_ssrc(), + // which is the SSRC of the corresponding outbound RTP stream, is unique. + std::vector GetLatestReportBlockData() const override; + + // (REMB) Receiver Estimated Max Bitrate. + void SetRemb(int64_t bitrate_bps, std::vector ssrcs) override; + void UnsetRemb() override; + + // (TMMBR) Temporary Max Media Bit Rate. + bool TMMBR() const override; + + void SetTMMBRStatus(bool enable) override; + + void SetTmmbn(std::vector bounding_set) override; + + size_t MaxRtpPacketSize() const override; + + void SetMaxRtpPacketSize(size_t max_packet_size) override; + + // (NACK) Negative acknowledgment part. + + // Send a Negative acknowledgment packet. + // TODO(philipel): Deprecate SendNACK and use SendNack instead. + int32_t SendNACK(const uint16_t* nack_list, uint16_t size) override; + + void SendNack(const std::vector& sequence_numbers) override; + + // Store the sent packets, needed to answer to a negative acknowledgment + // requests. + void SetStorePacketsStatus(bool enable, uint16_t number_to_store) override; + + bool StorePackets() const override; + + void SendCombinedRtcpPacket( + std::vector> rtcp_packets) override; + + // (APP) Application specific data. + int32_t SetRTCPApplicationSpecificData(uint8_t sub_type, + uint32_t name, + const uint8_t* data, + uint16_t length) override; + + // (XR) Receiver reference time report. + void SetRtcpXrRrtrStatus(bool enable) override; + + bool RtcpXrRrtrStatus() const override; + + // Video part. + int32_t SendLossNotification(uint16_t last_decoded_seq_num, + uint16_t last_received_seq_num, + bool decodability_flag, + bool buffering_allowed) override; + + bool LastReceivedNTP(uint32_t* NTPsecs, + uint32_t* NTPfrac, + uint32_t* remote_sr) const; + + void BitrateSent(uint32_t* total_rate, + uint32_t* video_rate, + uint32_t* fec_rate, + uint32_t* nackRate) const override; + + RtpSendRates GetSendRates() const override; + + void OnReceivedNack( + const std::vector& nack_sequence_numbers) override; + void OnReceivedRtcpReportBlocks( + const ReportBlockList& report_blocks) override; + void OnRequestSendReport() override; + + void SetVideoBitrateAllocation( + const VideoBitrateAllocation& bitrate) override; + + RTPSender* RtpSender() override; + const RTPSender* RtpSender() const override; + + protected: + bool UpdateRTCPReceiveInformationTimers(); + + RTPSender* rtp_sender() { + return rtp_sender_ ? &rtp_sender_->packet_generator : nullptr; + } + const RTPSender* rtp_sender() const { + return rtp_sender_ ? &rtp_sender_->packet_generator : nullptr; + } + + RTCPSender* rtcp_sender() { return &rtcp_sender_; } + const RTCPSender* rtcp_sender() const { return &rtcp_sender_; } + + RTCPReceiver* rtcp_receiver() { return &rtcp_receiver_; } + const RTCPReceiver* rtcp_receiver() const { return &rtcp_receiver_; } + + Clock* clock() const { return clock_; } + + // TODO(sprang): Remove when usage is gone. + DataRate SendRate() const; + DataRate NackOverheadRate() const; + + private: + FRIEND_TEST_ALL_PREFIXES(RtpRtcpImpl2Test, Rtt); + FRIEND_TEST_ALL_PREFIXES(RtpRtcpImpl2Test, RttForReceiverOnly); + + struct RtpSenderContext { + explicit RtpSenderContext(const RtpRtcp::Configuration& config); + // Storage of packets, for retransmissions and padding, if applicable. + RtpPacketHistory packet_history; + // Handles final time timestamping/stats/etc and handover to Transport. + RtpSenderEgress packet_sender; + // If no paced sender configured, this class will be used to pass packets + // from |packet_generator_| to |packet_sender_|. + RtpSenderEgress::NonPacedPacketSender non_paced_sender; + // Handles creation of RTP packets to be sent. + RTPSender packet_generator; + }; + + void set_rtt_ms(int64_t rtt_ms); + int64_t rtt_ms() const; + + bool TimeToSendFullNackList(int64_t now) const; + + SequenceChecker construction_thread_checker_; + SequenceChecker process_thread_checker_; + + std::unique_ptr rtp_sender_; + + RTCPSender rtcp_sender_; + RTCPReceiver rtcp_receiver_; + + Clock* const clock_; + + int64_t last_bitrate_process_time_; + int64_t last_rtt_process_time_; + int64_t next_process_time_; + uint16_t packet_overhead_; + + // Send side + int64_t nack_last_time_sent_full_ms_; + uint16_t nack_last_seq_number_sent_; + + RemoteBitrateEstimator* const remote_bitrate_; + + RtcpRttStats* const rtt_stats_; + + // The processed RTT from RtcpRttStats. + rtc::CriticalSection critical_section_rtt_; + int64_t rtt_ms_; +}; + +} // namespace webrtc + +#endif // MODULES_RTP_RTCP_SOURCE_RTP_RTCP_IMPL2_H_ diff --git a/modules/rtp_rtcp/source/rtp_rtcp_impl2_unittest.cc b/modules/rtp_rtcp/source/rtp_rtcp_impl2_unittest.cc new file mode 100644 index 0000000000..7627283e58 --- /dev/null +++ b/modules/rtp_rtcp/source/rtp_rtcp_impl2_unittest.cc @@ -0,0 +1,630 @@ +/* + * Copyright (c) 2013 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_rtcp_impl2.h" + +#include +#include +#include + +#include "api/transport/field_trial_based_config.h" +#include "api/video_codecs/video_codec.h" +#include "modules/rtp_rtcp/include/rtp_rtcp_defines.h" +#include "modules/rtp_rtcp/source/rtcp_packet.h" +#include "modules/rtp_rtcp/source/rtcp_packet/nack.h" +#include "modules/rtp_rtcp/source/rtp_packet_received.h" +#include "modules/rtp_rtcp/source/rtp_sender_video.h" +#include "rtc_base/rate_limiter.h" +#include "test/gmock.h" +#include "test/gtest.h" +#include "test/rtcp_packet_parser.h" +#include "test/rtp_header_parser.h" + +using ::testing::ElementsAre; + +namespace webrtc { +namespace { +const uint32_t kSenderSsrc = 0x12345; +const uint32_t kReceiverSsrc = 0x23456; +const int64_t kOneWayNetworkDelayMs = 100; +const uint8_t kBaseLayerTid = 0; +const uint8_t kHigherLayerTid = 1; +const uint16_t kSequenceNumber = 100; + +class RtcpRttStatsTestImpl : public RtcpRttStats { + public: + RtcpRttStatsTestImpl() : rtt_ms_(0) {} + ~RtcpRttStatsTestImpl() override = default; + + void OnRttUpdate(int64_t rtt_ms) override { rtt_ms_ = rtt_ms; } + int64_t LastProcessedRtt() const override { return rtt_ms_; } + int64_t rtt_ms_; +}; + +class SendTransport : public Transport { + public: + SendTransport() + : receiver_(nullptr), + clock_(nullptr), + delay_ms_(0), + rtp_packets_sent_(0), + rtcp_packets_sent_(0) {} + + void SetRtpRtcpModule(ModuleRtpRtcpImpl2* receiver) { receiver_ = receiver; } + void SimulateNetworkDelay(int64_t delay_ms, SimulatedClock* clock) { + clock_ = clock; + delay_ms_ = delay_ms; + } + bool SendRtp(const uint8_t* data, + size_t len, + const PacketOptions& options) override { + RTPHeader header; + std::unique_ptr parser(RtpHeaderParser::CreateForTest()); + EXPECT_TRUE(parser->Parse(static_cast(data), len, &header)); + ++rtp_packets_sent_; + last_rtp_header_ = header; + return true; + } + bool SendRtcp(const uint8_t* data, size_t len) override { + test::RtcpPacketParser parser; + parser.Parse(data, len); + last_nack_list_ = parser.nack()->packet_ids(); + + if (clock_) { + clock_->AdvanceTimeMilliseconds(delay_ms_); + } + EXPECT_TRUE(receiver_); + receiver_->IncomingRtcpPacket(data, len); + ++rtcp_packets_sent_; + return true; + } + size_t NumRtcpSent() { return rtcp_packets_sent_; } + ModuleRtpRtcpImpl2* receiver_; + SimulatedClock* clock_; + int64_t delay_ms_; + int rtp_packets_sent_; + size_t rtcp_packets_sent_; + RTPHeader last_rtp_header_; + std::vector last_nack_list_; +}; + +class RtpRtcpModule : public RtcpPacketTypeCounterObserver { + public: + RtpRtcpModule(SimulatedClock* clock, bool is_sender) + : is_sender_(is_sender), + receive_statistics_(ReceiveStatistics::Create(clock)), + clock_(clock) { + CreateModuleImpl(); + transport_.SimulateNetworkDelay(kOneWayNetworkDelayMs, clock); + } + + const bool is_sender_; + RtcpPacketTypeCounter packets_sent_; + RtcpPacketTypeCounter packets_received_; + std::unique_ptr receive_statistics_; + SendTransport transport_; + RtcpRttStatsTestImpl rtt_stats_; + std::unique_ptr impl_; + int rtcp_report_interval_ms_ = 0; + + void RtcpPacketTypesCounterUpdated( + uint32_t ssrc, + const RtcpPacketTypeCounter& packet_counter) override { + counter_map_[ssrc] = packet_counter; + } + + RtcpPacketTypeCounter RtcpSent() { + // RTCP counters for remote SSRC. + return counter_map_[is_sender_ ? kReceiverSsrc : kSenderSsrc]; + } + + RtcpPacketTypeCounter RtcpReceived() { + // Received RTCP stats for (own) local SSRC. + return counter_map_[impl_->SSRC()]; + } + int RtpSent() { return transport_.rtp_packets_sent_; } + uint16_t LastRtpSequenceNumber() { + return transport_.last_rtp_header_.sequenceNumber; + } + std::vector LastNackListSent() { + return transport_.last_nack_list_; + } + void SetRtcpReportIntervalAndReset(int rtcp_report_interval_ms) { + rtcp_report_interval_ms_ = rtcp_report_interval_ms; + CreateModuleImpl(); + } + + private: + void CreateModuleImpl() { + RtpRtcp::Configuration config; + config.audio = false; + config.clock = clock_; + config.outgoing_transport = &transport_; + config.receive_statistics = receive_statistics_.get(); + config.rtcp_packet_type_counter_observer = this; + config.rtt_stats = &rtt_stats_; + config.rtcp_report_interval_ms = rtcp_report_interval_ms_; + config.local_media_ssrc = is_sender_ ? kSenderSsrc : kReceiverSsrc; + config.need_rtp_packet_infos = true; + + impl_.reset(new ModuleRtpRtcpImpl2(config)); + impl_->SetRemoteSSRC(is_sender_ ? kReceiverSsrc : kSenderSsrc); + impl_->SetRTCPStatus(RtcpMode::kCompound); + } + + SimulatedClock* const clock_; + std::map counter_map_; +}; +} // namespace + +class RtpRtcpImpl2Test : public ::testing::Test { + protected: + RtpRtcpImpl2Test() + : clock_(133590000000000), + sender_(&clock_, /*is_sender=*/true), + receiver_(&clock_, /*is_sender=*/false) {} + + void SetUp() override { + // Send module. + EXPECT_EQ(0, sender_.impl_->SetSendingStatus(true)); + sender_.impl_->SetSendingMediaStatus(true); + sender_.impl_->SetSequenceNumber(kSequenceNumber); + sender_.impl_->SetStorePacketsStatus(true, 100); + + FieldTrialBasedConfig field_trials; + RTPSenderVideo::Config video_config; + video_config.clock = &clock_; + video_config.rtp_sender = sender_.impl_->RtpSender(); + video_config.field_trials = &field_trials; + sender_video_ = std::make_unique(video_config); + + memset(&codec_, 0, sizeof(VideoCodec)); + codec_.plType = 100; + codec_.width = 320; + codec_.height = 180; + + // Receive module. + EXPECT_EQ(0, receiver_.impl_->SetSendingStatus(false)); + receiver_.impl_->SetSendingMediaStatus(false); + // Transport settings. + sender_.transport_.SetRtpRtcpModule(receiver_.impl_.get()); + receiver_.transport_.SetRtpRtcpModule(sender_.impl_.get()); + } + + SimulatedClock clock_; + RtpRtcpModule sender_; + std::unique_ptr sender_video_; + RtpRtcpModule receiver_; + VideoCodec codec_; + + void SendFrame(const RtpRtcpModule* module, + RTPSenderVideo* sender, + uint8_t tid) { + RTPVideoHeaderVP8 vp8_header = {}; + vp8_header.temporalIdx = tid; + RTPVideoHeader rtp_video_header; + rtp_video_header.frame_type = VideoFrameType::kVideoFrameKey; + rtp_video_header.width = codec_.width; + rtp_video_header.height = codec_.height; + rtp_video_header.rotation = kVideoRotation_0; + rtp_video_header.content_type = VideoContentType::UNSPECIFIED; + rtp_video_header.playout_delay = {-1, -1}; + rtp_video_header.is_first_packet_in_frame = true; + rtp_video_header.simulcastIdx = 0; + rtp_video_header.codec = kVideoCodecVP8; + rtp_video_header.video_type_header = vp8_header; + rtp_video_header.video_timing = {0u, 0u, 0u, 0u, 0u, 0u, false}; + + const uint8_t payload[100] = {0}; + EXPECT_TRUE(module->impl_->OnSendingRtpFrame(0, 0, codec_.plType, true)); + EXPECT_TRUE(sender->SendVideo(codec_.plType, VideoCodecType::kVideoCodecVP8, + 0, 0, payload, nullptr, rtp_video_header, 0)); + } + + void IncomingRtcpNack(const RtpRtcpModule* module, uint16_t sequence_number) { + bool sender = module->impl_->SSRC() == kSenderSsrc; + rtcp::Nack nack; + uint16_t list[1]; + list[0] = sequence_number; + const uint16_t kListLength = sizeof(list) / sizeof(list[0]); + nack.SetSenderSsrc(sender ? kReceiverSsrc : kSenderSsrc); + nack.SetMediaSsrc(sender ? kSenderSsrc : kReceiverSsrc); + nack.SetPacketIds(list, kListLength); + rtc::Buffer packet = nack.Build(); + module->impl_->IncomingRtcpPacket(packet.data(), packet.size()); + } +}; + +TEST_F(RtpRtcpImpl2Test, RetransmitsAllLayers) { + // Send frames. + EXPECT_EQ(0, sender_.RtpSent()); + SendFrame(&sender_, sender_video_.get(), kBaseLayerTid); // kSequenceNumber + SendFrame(&sender_, sender_video_.get(), + kHigherLayerTid); // kSequenceNumber + 1 + SendFrame(&sender_, sender_video_.get(), + kNoTemporalIdx); // kSequenceNumber + 2 + EXPECT_EQ(3, sender_.RtpSent()); + EXPECT_EQ(kSequenceNumber + 2, sender_.LastRtpSequenceNumber()); + + // Min required delay until retransmit = 5 + RTT ms (RTT = 0). + clock_.AdvanceTimeMilliseconds(5); + + // Frame with kBaseLayerTid re-sent. + IncomingRtcpNack(&sender_, kSequenceNumber); + EXPECT_EQ(4, sender_.RtpSent()); + EXPECT_EQ(kSequenceNumber, sender_.LastRtpSequenceNumber()); + // Frame with kHigherLayerTid re-sent. + IncomingRtcpNack(&sender_, kSequenceNumber + 1); + EXPECT_EQ(5, sender_.RtpSent()); + EXPECT_EQ(kSequenceNumber + 1, sender_.LastRtpSequenceNumber()); + // Frame with kNoTemporalIdx re-sent. + IncomingRtcpNack(&sender_, kSequenceNumber + 2); + EXPECT_EQ(6, sender_.RtpSent()); + EXPECT_EQ(kSequenceNumber + 2, sender_.LastRtpSequenceNumber()); +} + +TEST_F(RtpRtcpImpl2Test, Rtt) { + RtpPacketReceived packet; + packet.SetTimestamp(1); + packet.SetSequenceNumber(123); + packet.SetSsrc(kSenderSsrc); + packet.AllocatePayload(100 - 12); + receiver_.receive_statistics_->OnRtpPacket(packet); + + // Send Frame before sending an SR. + SendFrame(&sender_, sender_video_.get(), kBaseLayerTid); + // Sender module should send an SR. + EXPECT_EQ(0, sender_.impl_->SendRTCP(kRtcpReport)); + + // Receiver module should send a RR with a response to the last received SR. + clock_.AdvanceTimeMilliseconds(1000); + EXPECT_EQ(0, receiver_.impl_->SendRTCP(kRtcpReport)); + + // Verify RTT. + int64_t rtt; + int64_t avg_rtt; + int64_t min_rtt; + int64_t max_rtt; + EXPECT_EQ( + 0, sender_.impl_->RTT(kReceiverSsrc, &rtt, &avg_rtt, &min_rtt, &max_rtt)); + EXPECT_NEAR(2 * kOneWayNetworkDelayMs, rtt, 1); + EXPECT_NEAR(2 * kOneWayNetworkDelayMs, avg_rtt, 1); + EXPECT_NEAR(2 * kOneWayNetworkDelayMs, min_rtt, 1); + EXPECT_NEAR(2 * kOneWayNetworkDelayMs, max_rtt, 1); + + // No RTT from other ssrc. + EXPECT_EQ(-1, sender_.impl_->RTT(kReceiverSsrc + 1, &rtt, &avg_rtt, &min_rtt, + &max_rtt)); + + // Verify RTT from rtt_stats config. + EXPECT_EQ(0, sender_.rtt_stats_.LastProcessedRtt()); + EXPECT_EQ(0, sender_.impl_->rtt_ms()); + sender_.impl_->Process(); + EXPECT_NEAR(2 * kOneWayNetworkDelayMs, sender_.rtt_stats_.LastProcessedRtt(), + 1); + EXPECT_NEAR(2 * kOneWayNetworkDelayMs, sender_.impl_->rtt_ms(), 1); +} + +TEST_F(RtpRtcpImpl2Test, SetRtcpXrRrtrStatus) { + EXPECT_FALSE(receiver_.impl_->RtcpXrRrtrStatus()); + receiver_.impl_->SetRtcpXrRrtrStatus(true); + EXPECT_TRUE(receiver_.impl_->RtcpXrRrtrStatus()); +} + +TEST_F(RtpRtcpImpl2Test, RttForReceiverOnly) { + receiver_.impl_->SetRtcpXrRrtrStatus(true); + + // Receiver module should send a Receiver time reference report (RTRR). + EXPECT_EQ(0, receiver_.impl_->SendRTCP(kRtcpReport)); + + // Sender module should send a response to the last received RTRR (DLRR). + clock_.AdvanceTimeMilliseconds(1000); + // Send Frame before sending a SR. + SendFrame(&sender_, sender_video_.get(), kBaseLayerTid); + EXPECT_EQ(0, sender_.impl_->SendRTCP(kRtcpReport)); + + // Verify RTT. + EXPECT_EQ(0, receiver_.rtt_stats_.LastProcessedRtt()); + EXPECT_EQ(0, receiver_.impl_->rtt_ms()); + receiver_.impl_->Process(); + EXPECT_NEAR(2 * kOneWayNetworkDelayMs, + receiver_.rtt_stats_.LastProcessedRtt(), 1); + EXPECT_NEAR(2 * kOneWayNetworkDelayMs, receiver_.impl_->rtt_ms(), 1); +} + +TEST_F(RtpRtcpImpl2Test, NoSrBeforeMedia) { + // Ignore fake transport delays in this test. + sender_.transport_.SimulateNetworkDelay(0, &clock_); + receiver_.transport_.SimulateNetworkDelay(0, &clock_); + + sender_.impl_->Process(); + EXPECT_EQ(-1, sender_.RtcpSent().first_packet_time_ms); + + // Verify no SR is sent before media has been sent, RR should still be sent + // from the receiving module though. + clock_.AdvanceTimeMilliseconds(2000); + int64_t current_time = clock_.TimeInMilliseconds(); + sender_.impl_->Process(); + receiver_.impl_->Process(); + EXPECT_EQ(-1, sender_.RtcpSent().first_packet_time_ms); + EXPECT_EQ(receiver_.RtcpSent().first_packet_time_ms, current_time); + + SendFrame(&sender_, sender_video_.get(), kBaseLayerTid); + EXPECT_EQ(sender_.RtcpSent().first_packet_time_ms, current_time); +} + +TEST_F(RtpRtcpImpl2Test, RtcpPacketTypeCounter_Nack) { + EXPECT_EQ(-1, receiver_.RtcpSent().first_packet_time_ms); + EXPECT_EQ(-1, sender_.RtcpReceived().first_packet_time_ms); + EXPECT_EQ(0U, sender_.RtcpReceived().nack_packets); + EXPECT_EQ(0U, receiver_.RtcpSent().nack_packets); + + // Receive module sends a NACK. + const uint16_t kNackLength = 1; + uint16_t nack_list[kNackLength] = {123}; + EXPECT_EQ(0, receiver_.impl_->SendNACK(nack_list, kNackLength)); + EXPECT_EQ(1U, receiver_.RtcpSent().nack_packets); + EXPECT_GT(receiver_.RtcpSent().first_packet_time_ms, -1); + + // Send module receives the NACK. + EXPECT_EQ(1U, sender_.RtcpReceived().nack_packets); + EXPECT_GT(sender_.RtcpReceived().first_packet_time_ms, -1); +} + +TEST_F(RtpRtcpImpl2Test, AddStreamDataCounters) { + StreamDataCounters rtp; + const int64_t kStartTimeMs = 1; + rtp.first_packet_time_ms = kStartTimeMs; + rtp.transmitted.packets = 1; + rtp.transmitted.payload_bytes = 1; + rtp.transmitted.header_bytes = 2; + rtp.transmitted.padding_bytes = 3; + EXPECT_EQ(rtp.transmitted.TotalBytes(), rtp.transmitted.payload_bytes + + rtp.transmitted.header_bytes + + rtp.transmitted.padding_bytes); + + StreamDataCounters rtp2; + rtp2.first_packet_time_ms = -1; + rtp2.transmitted.packets = 10; + rtp2.transmitted.payload_bytes = 10; + rtp2.retransmitted.header_bytes = 4; + rtp2.retransmitted.payload_bytes = 5; + rtp2.retransmitted.padding_bytes = 6; + rtp2.retransmitted.packets = 7; + rtp2.fec.packets = 8; + + StreamDataCounters sum = rtp; + sum.Add(rtp2); + EXPECT_EQ(kStartTimeMs, sum.first_packet_time_ms); + EXPECT_EQ(11U, sum.transmitted.packets); + EXPECT_EQ(11U, sum.transmitted.payload_bytes); + EXPECT_EQ(2U, sum.transmitted.header_bytes); + EXPECT_EQ(3U, sum.transmitted.padding_bytes); + EXPECT_EQ(4U, sum.retransmitted.header_bytes); + EXPECT_EQ(5U, sum.retransmitted.payload_bytes); + EXPECT_EQ(6U, sum.retransmitted.padding_bytes); + EXPECT_EQ(7U, sum.retransmitted.packets); + EXPECT_EQ(8U, sum.fec.packets); + EXPECT_EQ(sum.transmitted.TotalBytes(), + rtp.transmitted.TotalBytes() + rtp2.transmitted.TotalBytes()); + + StreamDataCounters rtp3; + rtp3.first_packet_time_ms = kStartTimeMs + 10; + sum.Add(rtp3); + EXPECT_EQ(kStartTimeMs, sum.first_packet_time_ms); // Holds oldest time. +} + +TEST_F(RtpRtcpImpl2Test, SendsInitialNackList) { + // Send module sends a NACK. + const uint16_t kNackLength = 1; + uint16_t nack_list[kNackLength] = {123}; + EXPECT_EQ(0U, sender_.RtcpSent().nack_packets); + // Send Frame before sending a compound RTCP that starts with SR. + SendFrame(&sender_, sender_video_.get(), kBaseLayerTid); + EXPECT_EQ(0, sender_.impl_->SendNACK(nack_list, kNackLength)); + EXPECT_EQ(1U, sender_.RtcpSent().nack_packets); + EXPECT_THAT(sender_.LastNackListSent(), ElementsAre(123)); +} + +TEST_F(RtpRtcpImpl2Test, SendsExtendedNackList) { + // Send module sends a NACK. + const uint16_t kNackLength = 1; + uint16_t nack_list[kNackLength] = {123}; + EXPECT_EQ(0U, sender_.RtcpSent().nack_packets); + // Send Frame before sending a compound RTCP that starts with SR. + SendFrame(&sender_, sender_video_.get(), kBaseLayerTid); + EXPECT_EQ(0, sender_.impl_->SendNACK(nack_list, kNackLength)); + EXPECT_EQ(1U, sender_.RtcpSent().nack_packets); + EXPECT_THAT(sender_.LastNackListSent(), ElementsAre(123)); + + // Same list not re-send. + EXPECT_EQ(0, sender_.impl_->SendNACK(nack_list, kNackLength)); + EXPECT_EQ(1U, sender_.RtcpSent().nack_packets); + EXPECT_THAT(sender_.LastNackListSent(), ElementsAre(123)); + + // Only extended list sent. + const uint16_t kNackExtLength = 2; + uint16_t nack_list_ext[kNackExtLength] = {123, 124}; + EXPECT_EQ(0, sender_.impl_->SendNACK(nack_list_ext, kNackExtLength)); + EXPECT_EQ(2U, sender_.RtcpSent().nack_packets); + EXPECT_THAT(sender_.LastNackListSent(), ElementsAre(124)); +} + +TEST_F(RtpRtcpImpl2Test, ReSendsNackListAfterRttMs) { + sender_.transport_.SimulateNetworkDelay(0, &clock_); + // Send module sends a NACK. + const uint16_t kNackLength = 2; + uint16_t nack_list[kNackLength] = {123, 125}; + EXPECT_EQ(0U, sender_.RtcpSent().nack_packets); + // Send Frame before sending a compound RTCP that starts with SR. + SendFrame(&sender_, sender_video_.get(), kBaseLayerTid); + EXPECT_EQ(0, sender_.impl_->SendNACK(nack_list, kNackLength)); + EXPECT_EQ(1U, sender_.RtcpSent().nack_packets); + EXPECT_THAT(sender_.LastNackListSent(), ElementsAre(123, 125)); + + // Same list not re-send, rtt interval has not passed. + const int kStartupRttMs = 100; + clock_.AdvanceTimeMilliseconds(kStartupRttMs); + EXPECT_EQ(0, sender_.impl_->SendNACK(nack_list, kNackLength)); + EXPECT_EQ(1U, sender_.RtcpSent().nack_packets); + + // Rtt interval passed, full list sent. + clock_.AdvanceTimeMilliseconds(1); + EXPECT_EQ(0, sender_.impl_->SendNACK(nack_list, kNackLength)); + EXPECT_EQ(2U, sender_.RtcpSent().nack_packets); + EXPECT_THAT(sender_.LastNackListSent(), ElementsAre(123, 125)); +} + +TEST_F(RtpRtcpImpl2Test, UniqueNackRequests) { + receiver_.transport_.SimulateNetworkDelay(0, &clock_); + EXPECT_EQ(0U, receiver_.RtcpSent().nack_packets); + EXPECT_EQ(0U, receiver_.RtcpSent().nack_requests); + EXPECT_EQ(0U, receiver_.RtcpSent().unique_nack_requests); + EXPECT_EQ(0, receiver_.RtcpSent().UniqueNackRequestsInPercent()); + + // Receive module sends NACK request. + const uint16_t kNackLength = 4; + uint16_t nack_list[kNackLength] = {10, 11, 13, 18}; + EXPECT_EQ(0, receiver_.impl_->SendNACK(nack_list, kNackLength)); + EXPECT_EQ(1U, receiver_.RtcpSent().nack_packets); + EXPECT_EQ(4U, receiver_.RtcpSent().nack_requests); + EXPECT_EQ(4U, receiver_.RtcpSent().unique_nack_requests); + EXPECT_THAT(receiver_.LastNackListSent(), ElementsAre(10, 11, 13, 18)); + + // Send module receives the request. + EXPECT_EQ(1U, sender_.RtcpReceived().nack_packets); + EXPECT_EQ(4U, sender_.RtcpReceived().nack_requests); + EXPECT_EQ(4U, sender_.RtcpReceived().unique_nack_requests); + EXPECT_EQ(100, sender_.RtcpReceived().UniqueNackRequestsInPercent()); + + // Receive module sends new request with duplicated packets. + const int kStartupRttMs = 100; + clock_.AdvanceTimeMilliseconds(kStartupRttMs + 1); + const uint16_t kNackLength2 = 4; + uint16_t nack_list2[kNackLength2] = {11, 18, 20, 21}; + EXPECT_EQ(0, receiver_.impl_->SendNACK(nack_list2, kNackLength2)); + EXPECT_EQ(2U, receiver_.RtcpSent().nack_packets); + EXPECT_EQ(8U, receiver_.RtcpSent().nack_requests); + EXPECT_EQ(6U, receiver_.RtcpSent().unique_nack_requests); + EXPECT_THAT(receiver_.LastNackListSent(), ElementsAre(11, 18, 20, 21)); + + // Send module receives the request. + EXPECT_EQ(2U, sender_.RtcpReceived().nack_packets); + EXPECT_EQ(8U, sender_.RtcpReceived().nack_requests); + EXPECT_EQ(6U, sender_.RtcpReceived().unique_nack_requests); + EXPECT_EQ(75, sender_.RtcpReceived().UniqueNackRequestsInPercent()); +} + +TEST_F(RtpRtcpImpl2Test, ConfigurableRtcpReportInterval) { + const int kVideoReportInterval = 3000; + + // Recreate sender impl with new configuration, and redo setup. + sender_.SetRtcpReportIntervalAndReset(kVideoReportInterval); + SetUp(); + + SendFrame(&sender_, sender_video_.get(), kBaseLayerTid); + + // Initial state + sender_.impl_->Process(); + EXPECT_EQ(sender_.RtcpSent().first_packet_time_ms, -1); + EXPECT_EQ(0u, sender_.transport_.NumRtcpSent()); + + // Move ahead to the last ms before a rtcp is expected, no action. + clock_.AdvanceTimeMilliseconds(kVideoReportInterval / 2 - 1); + sender_.impl_->Process(); + EXPECT_EQ(sender_.RtcpSent().first_packet_time_ms, -1); + EXPECT_EQ(sender_.transport_.NumRtcpSent(), 0u); + + // Move ahead to the first rtcp. Send RTCP. + clock_.AdvanceTimeMilliseconds(1); + sender_.impl_->Process(); + EXPECT_GT(sender_.RtcpSent().first_packet_time_ms, -1); + EXPECT_EQ(sender_.transport_.NumRtcpSent(), 1u); + + SendFrame(&sender_, sender_video_.get(), kBaseLayerTid); + + // Move ahead to the last possible second before second rtcp is expected. + clock_.AdvanceTimeMilliseconds(kVideoReportInterval * 1 / 2 - 1); + sender_.impl_->Process(); + EXPECT_EQ(sender_.transport_.NumRtcpSent(), 1u); + + // Move ahead into the range of second rtcp, the second rtcp may be sent. + clock_.AdvanceTimeMilliseconds(1); + sender_.impl_->Process(); + EXPECT_GE(sender_.transport_.NumRtcpSent(), 1u); + + clock_.AdvanceTimeMilliseconds(kVideoReportInterval / 2); + sender_.impl_->Process(); + EXPECT_GE(sender_.transport_.NumRtcpSent(), 1u); + + // Move out the range of second rtcp, the second rtcp must have been sent. + clock_.AdvanceTimeMilliseconds(kVideoReportInterval / 2); + sender_.impl_->Process(); + EXPECT_EQ(sender_.transport_.NumRtcpSent(), 2u); +} + +TEST_F(RtpRtcpImpl2Test, StoresPacketInfoForSentPackets) { + const uint32_t kStartTimestamp = 1u; + SetUp(); + sender_.impl_->SetStartTimestamp(kStartTimestamp); + + PacedPacketInfo pacing_info; + RtpPacketToSend packet(nullptr); + packet.set_packet_type(RtpPacketToSend::Type::kVideo); + packet.SetSsrc(kSenderSsrc); + + // Single-packet frame. + packet.SetTimestamp(1); + packet.SetSequenceNumber(1); + packet.set_first_packet_of_frame(true); + packet.SetMarker(true); + sender_.impl_->TrySendPacket(&packet, pacing_info); + + std::vector seqno_info = + sender_.impl_->GetSentRtpPacketInfos(std::vector{1}); + + EXPECT_THAT(seqno_info, ElementsAre(RtpSequenceNumberMap::Info( + /*timestamp=*/1 - kStartTimestamp, + /*is_first=*/1, + /*is_last=*/1))); + + // Three-packet frame. + packet.SetTimestamp(2); + packet.SetSequenceNumber(2); + packet.set_first_packet_of_frame(true); + packet.SetMarker(false); + sender_.impl_->TrySendPacket(&packet, pacing_info); + + packet.SetSequenceNumber(3); + packet.set_first_packet_of_frame(false); + sender_.impl_->TrySendPacket(&packet, pacing_info); + + packet.SetSequenceNumber(4); + packet.SetMarker(true); + sender_.impl_->TrySendPacket(&packet, pacing_info); + + seqno_info = + sender_.impl_->GetSentRtpPacketInfos(std::vector{2, 3, 4}); + + EXPECT_THAT(seqno_info, ElementsAre(RtpSequenceNumberMap::Info( + /*timestamp=*/2 - kStartTimestamp, + /*is_first=*/1, + /*is_last=*/0), + RtpSequenceNumberMap::Info( + /*timestamp=*/2 - kStartTimestamp, + /*is_first=*/0, + /*is_last=*/0), + RtpSequenceNumberMap::Info( + /*timestamp=*/2 - kStartTimestamp, + /*is_first=*/0, + /*is_last=*/1))); +} + +} // namespace webrtc diff --git a/video/end_to_end_tests/bandwidth_tests.cc b/video/end_to_end_tests/bandwidth_tests.cc index 16b35d68f8..6e8e11d76f 100644 --- a/video/end_to_end_tests/bandwidth_tests.cc +++ b/video/end_to_end_tests/bandwidth_tests.cc @@ -205,8 +205,9 @@ TEST_F(BandwidthEndToEndTest, RembWithSendSideBwe) { ~BweObserver() override { // Block until all already posted tasks run to avoid races when such task - // accesses |this|. - SendTask(RTC_FROM_HERE, task_queue_, [] {}); + // accesses |this|. Also make sure we free |rtp_rtcp_| on the correct + // thread/task queue. + SendTask(RTC_FROM_HERE, task_queue_, [this]() { rtp_rtcp_ = nullptr; }); } std::unique_ptr CreateReceiveTransport( diff --git a/video/video_send_stream_tests.cc b/video/video_send_stream_tests.cc index e38653831b..63acb80b8d 100644 --- a/video/video_send_stream_tests.cc +++ b/video/video_send_stream_tests.cc @@ -1627,12 +1627,18 @@ TEST_F(VideoSendStreamTest, MinTransmitBitrateRespectsRemb) { static const int kRembRespectedBitrateBps = 100000; class BitrateObserver : public test::SendTest { public: - BitrateObserver() + explicit BitrateObserver(TaskQueueBase* task_queue) : SendTest(kDefaultTimeoutMs), + task_queue_(task_queue), retranmission_rate_limiter_(Clock::GetRealTimeClock(), 1000), stream_(nullptr), bitrate_capped_(false) {} + ~BitrateObserver() override { + // Make sure we free |rtp_rtcp_| in the same context as we constructed it. + SendTask(RTC_FROM_HERE, task_queue_, [this]() { rtp_rtcp_ = nullptr; }); + } + private: Action OnSendRtp(const uint8_t* packet, size_t length) override { if (RtpHeaderParser::IsRtcp(packet, length)) @@ -1690,12 +1696,13 @@ TEST_F(VideoSendStreamTest, MinTransmitBitrateRespectsRemb) { << "Timeout while waiting for low bitrate stats after REMB."; } + TaskQueueBase* const task_queue_; std::unique_ptr rtp_rtcp_; std::unique_ptr feedback_transport_; RateLimiter retranmission_rate_limiter_; VideoSendStream* stream_; bool bitrate_capped_; - } test; + } test(task_queue()); RunBaseTest(&test); }