From 13ef7d25f69f9d47605c8c691fd717a92467d833 Mon Sep 17 00:00:00 2001 From: Sebastian Jansson Date: Mon, 6 Aug 2018 13:20:36 +0200 Subject: [PATCH] Adds feedback only mode to GoogCC. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This CL adds a factory for creating a GoogCC network controller that can be used without RTCP specific messages. This prepares for enabling use of other underlying protocols as long as they can provide per packet feedback. Bug: None Change-Id: I6671181949d97abd18843d0f4edf75040cc3f007 Reviewed-on: https://webrtc-review.googlesource.com/84583 Commit-Queue: Sebastian Jansson Reviewed-by: Björn Terelius Cr-Commit-Position: refs/heads/master@{#24198} --- .../goog_cc/goog_cc_factory.cc | 17 +++- .../goog_cc/goog_cc_network_control.cc | 91 ++++++++++++++----- .../goog_cc/goog_cc_network_control.h | 12 ++- .../goog_cc/include/goog_cc_factory.h | 14 +++ 4 files changed, 109 insertions(+), 25 deletions(-) diff --git a/modules/congestion_controller/goog_cc/goog_cc_factory.cc b/modules/congestion_controller/goog_cc/goog_cc_factory.cc index d4a40f179a..077c8a7b6d 100644 --- a/modules/congestion_controller/goog_cc/goog_cc_factory.cc +++ b/modules/congestion_controller/goog_cc/goog_cc_factory.cc @@ -20,11 +20,26 @@ GoogCcNetworkControllerFactory::GoogCcNetworkControllerFactory( std::unique_ptr GoogCcNetworkControllerFactory::Create(NetworkControllerConfig config) { return absl::make_unique(event_log_, - config); + config, false); } TimeDelta GoogCcNetworkControllerFactory::GetProcessInterval() const { const int64_t kUpdateIntervalMs = 25; return TimeDelta::ms(kUpdateIntervalMs); } + +GoogCcFeedbackNetworkControllerFactory::GoogCcFeedbackNetworkControllerFactory( + RtcEventLog* event_log) + : event_log_(event_log) {} + +std::unique_ptr +GoogCcFeedbackNetworkControllerFactory::Create(NetworkControllerConfig config) { + return absl::make_unique(event_log_, + config, true); +} + +TimeDelta GoogCcFeedbackNetworkControllerFactory::GetProcessInterval() const { + const int64_t kUpdateIntervalMs = 25; + return TimeDelta::ms(kUpdateIntervalMs); +} } // namespace webrtc diff --git a/modules/congestion_controller/goog_cc/goog_cc_network_control.cc b/modules/congestion_controller/goog_cc/goog_cc_network_control.cc index ef000126b5..cb8895a4a2 100644 --- a/modules/congestion_controller/goog_cc/goog_cc_network_control.cc +++ b/modules/congestion_controller/goog_cc/goog_cc_network_control.cc @@ -14,6 +14,7 @@ #include #include #include +#include #include #include #include @@ -38,6 +39,9 @@ namespace { const char kCwndExperiment[] = "WebRTC-CwndExperiment"; const int64_t kDefaultAcceptedQueueMs = 250; +// From RTCPSender video report interval. +const TimeDelta kLossUpdateInterval = TimeDelta::ms(1000); + // Pacing-rate relative to our target send rate. // Multiplicative factor that is applied to the target bitrate to calculate // the number of bytes that can be transmitted per interval. @@ -113,8 +117,10 @@ int64_t GetBpsOrDefault(const absl::optional& rate, } // namespace GoogCcNetworkController::GoogCcNetworkController(RtcEventLog* event_log, - NetworkControllerConfig config) + NetworkControllerConfig config, + bool feedback_only) : event_log_(event_log), + packet_feedback_only_(feedback_only), probe_controller_(new ProbeController()), bandwidth_estimation_( absl::make_unique(event_log_)), @@ -214,6 +220,10 @@ NetworkControlUpdate GoogCcNetworkController::OnProcessInterval( NetworkControlUpdate GoogCcNetworkController::OnRemoteBitrateReport( RemoteBitrateReport msg) { + if (packet_feedback_only_) { + RTC_LOG(LS_ERROR) << "Received REMB for packet feedback only GoogCC"; + return NetworkControlUpdate(); + } bandwidth_estimation_->UpdateReceiverEstimate(msg.receive_time.ms(), msg.bandwidth.bps()); BWE_TEST_LOGGING_PLOT(1, "REMB_kbps", msg.receive_time.ms(), @@ -223,6 +233,8 @@ NetworkControlUpdate GoogCcNetworkController::OnRemoteBitrateReport( NetworkControlUpdate GoogCcNetworkController::OnRoundTripTimeUpdate( RoundTripTimeUpdate msg) { + if (packet_feedback_only_) + return NetworkControlUpdate(); if (msg.smoothed) { delay_based_bwe_->OnRttUpdate(msg.round_trip_time.ms()); } else { @@ -301,6 +313,8 @@ GoogCcNetworkController::UpdateBitrateConstraints( NetworkControlUpdate GoogCcNetworkController::OnTransportLossReport( TransportLossReport msg) { + if (packet_feedback_only_) + return NetworkControlUpdate(); int64_t total_packets_delta = msg.packets_received_delta + msg.packets_lost_delta; bandwidth_estimation_->UpdatePacketsLost( @@ -310,24 +324,59 @@ NetworkControlUpdate GoogCcNetworkController::OnTransportLossReport( NetworkControlUpdate GoogCcNetworkController::OnTransportPacketsFeedback( TransportPacketsFeedback report) { - int64_t feedback_rtt = -1; - for (const auto& packet_feedback : report.PacketsWithFeedback()) { - if (packet_feedback.sent_packet.has_value() && - packet_feedback.receive_time.IsFinite()) { - int64_t rtt = report.feedback_time.ms() - - packet_feedback.sent_packet->send_time.ms(); - // max() is used to account for feedback being delayed by the - // receiver. - feedback_rtt = std::max(rtt, feedback_rtt); - } + TimeDelta feedback_max_rtt = TimeDelta::MinusInfinity(); + Timestamp max_recv_time = Timestamp::ms(0); + for (const auto& packet_feedback : report.ReceivedWithSendInfo()) { + TimeDelta rtt = + report.feedback_time - packet_feedback.sent_packet->send_time; + // max() is used to account for feedback being delayed by the + // receiver. + feedback_max_rtt = std::max(feedback_max_rtt, rtt); + max_recv_time = std::max(max_recv_time, packet_feedback.receive_time); } - if (feedback_rtt > -1) { - feedback_rtts_.push_back(feedback_rtt); - const size_t kFeedbackRttWindow = 32; - if (feedback_rtts_.size() > kFeedbackRttWindow) - feedback_rtts_.pop_front(); - min_feedback_rtt_ms_.emplace( - *std::min_element(feedback_rtts_.begin(), feedback_rtts_.end())); + if (feedback_max_rtt.IsFinite()) { + feedback_max_rtts_.push_back(feedback_max_rtt.ms()); + const size_t kMaxFeedbackRttWindow = 32; + if (feedback_max_rtts_.size() > kMaxFeedbackRttWindow) + feedback_max_rtts_.pop_front(); + min_feedback_max_rtt_ms_.emplace(*std::min_element( + feedback_max_rtts_.begin(), feedback_max_rtts_.end())); + } + if (packet_feedback_only_) { + if (!feedback_max_rtts_.empty()) { + int64_t sum_rtt_ms = std::accumulate(feedback_max_rtts_.begin(), + feedback_max_rtts_.end(), 0); + int64_t mean_rtt_ms = sum_rtt_ms / feedback_max_rtts_.size(); + delay_based_bwe_->OnRttUpdate(mean_rtt_ms); + } + + TimeDelta feedback_min_rtt = TimeDelta::PlusInfinity(); + for (const auto& packet_feedback : report.ReceivedWithSendInfo()) { + TimeDelta pending_time = packet_feedback.receive_time - max_recv_time; + TimeDelta rtt = report.feedback_time - + packet_feedback.sent_packet->send_time - pending_time; + // Value used for predicting NACK round trip time in FEC controller. + feedback_min_rtt = std::min(rtt, feedback_min_rtt); + } + if (feedback_min_rtt.IsFinite()) { + bandwidth_estimation_->UpdateRtt(feedback_min_rtt.ms(), + report.feedback_time.ms()); + } + + expected_packets_since_last_loss_update_ += + report.PacketsWithFeedback().size(); + for (const auto& packet_feedback : report.PacketsWithFeedback()) { + lost_packets_since_last_loss_update_ += + packet_feedback.receive_time.IsFinite() ? 0 : 1; + } + if (report.feedback_time > next_loss_update_) { + next_loss_update_ += kLossUpdateInterval; + bandwidth_estimation_->UpdatePacketsLost( + expected_packets_since_last_loss_update_, + lost_packets_since_last_loss_update_, report.feedback_time.ms()); + expected_packets_since_last_loss_update_ = 0; + lost_packets_since_last_loss_update_ = 0; + } } std::vector received_feedback_vector = @@ -396,12 +445,12 @@ GoogCcNetworkController::MaybeUpdateCongestionWindow() { return absl::nullopt; // No valid RTT. Could be because send-side BWE isn't used, in which case // we don't try to limit the outstanding packets. - if (!min_feedback_rtt_ms_) + if (!min_feedback_max_rtt_ms_) return absl::nullopt; const DataSize kMinCwnd = DataSize::bytes(2 * 1500); TimeDelta time_window = - TimeDelta::ms(*min_feedback_rtt_ms_ + accepted_queue_ms_); + TimeDelta::ms(*min_feedback_max_rtt_ms_ + accepted_queue_ms_); DataSize data_window = last_bandwidth_ * time_window; if (current_data_window_) { data_window = @@ -410,7 +459,7 @@ GoogCcNetworkController::MaybeUpdateCongestionWindow() { data_window = std::max(kMinCwnd, data_window); } current_data_window_ = data_window; - RTC_LOG(LS_INFO) << "Feedback rtt: " << *min_feedback_rtt_ms_ + RTC_LOG(LS_INFO) << "Feedback rtt: " << *min_feedback_max_rtt_ms_ << " Bitrate: " << last_bandwidth_.bps(); return data_window; } diff --git a/modules/congestion_controller/goog_cc/goog_cc_network_control.h b/modules/congestion_controller/goog_cc/goog_cc_network_control.h index 88b487402b..59f0b15311 100644 --- a/modules/congestion_controller/goog_cc/goog_cc_network_control.h +++ b/modules/congestion_controller/goog_cc/goog_cc_network_control.h @@ -32,7 +32,8 @@ namespace webrtc_cc { class GoogCcNetworkController : public NetworkControllerInterface { public: GoogCcNetworkController(RtcEventLog* event_log, - NetworkControllerConfig config); + NetworkControllerConfig config, + bool feedback_only); ~GoogCcNetworkController() override; // NetworkControllerInterface @@ -65,6 +66,7 @@ class GoogCcNetworkController : public NetworkControllerInterface { PacerConfig GetPacingRates(Timestamp at_time) const; RtcEventLog* const event_log_; + const bool packet_feedback_only_; const std::unique_ptr probe_controller_; @@ -75,8 +77,12 @@ class GoogCcNetworkController : public NetworkControllerInterface { absl::optional initial_config_; - std::deque feedback_rtts_; - absl::optional min_feedback_rtt_ms_; + Timestamp next_loss_update_ = Timestamp::ms(0); + int lost_packets_since_last_loss_update_ = 0; + int expected_packets_since_last_loss_update_ = 0; + + std::deque feedback_max_rtts_; + absl::optional min_feedback_max_rtt_ms_; DataRate last_bandwidth_; absl::optional last_target_rate_; diff --git a/modules/congestion_controller/goog_cc/include/goog_cc_factory.h b/modules/congestion_controller/goog_cc/include/goog_cc_factory.h index f4eea11366..0d91fff65f 100644 --- a/modules/congestion_controller/goog_cc/include/goog_cc_factory.h +++ b/modules/congestion_controller/goog_cc/include/goog_cc_factory.h @@ -29,6 +29,20 @@ class GoogCcNetworkControllerFactory private: RtcEventLog* const event_log_; }; + +// Factory to create packet feedback only GoogCC, this can be used for +// connections providing packet receive time feedback but no other reports. +class GoogCcFeedbackNetworkControllerFactory + : public NetworkControllerFactoryInterface { + public: + explicit GoogCcFeedbackNetworkControllerFactory(RtcEventLog*); + std::unique_ptr Create( + NetworkControllerConfig config) override; + TimeDelta GetProcessInterval() const override; + + private: + RtcEventLog* const event_log_; +}; } // namespace webrtc #endif // MODULES_CONGESTION_CONTROLLER_GOOG_CC_INCLUDE_GOOG_CC_FACTORY_H_