diff options
Diffstat (limited to 'chromium/media/cast/congestion_control/congestion_control.cc')
-rw-r--r-- | chromium/media/cast/congestion_control/congestion_control.cc | 112 |
1 files changed, 112 insertions, 0 deletions
diff --git a/chromium/media/cast/congestion_control/congestion_control.cc b/chromium/media/cast/congestion_control/congestion_control.cc new file mode 100644 index 00000000000..f8ca98c2c9a --- /dev/null +++ b/chromium/media/cast/congestion_control/congestion_control.cc @@ -0,0 +1,112 @@ +// Copyright 2013 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "media/cast/congestion_control/congestion_control.h" + +#include "base/logging.h" +#include "media/cast/cast_config.h" +#include "media/cast/cast_defines.h" + +namespace media { +namespace cast { + +static const int64 kCongestionControlMinChangeIntervalMs = 10; +static const int64 kCongestionControlMaxChangeIntervalMs = 100; + +// At 10 ms RTT TCP Reno would ramp 1500 * 8 * 100 = 1200 Kbit/s. +// NACK is sent after a maximum of 10 ms. +static const int kCongestionControlMaxBitrateIncreasePerMillisecond = 1200; + +static const int64 kMaxElapsedTimeMs = kCongestionControlMaxChangeIntervalMs; + +CongestionControl::CongestionControl(float congestion_control_back_off, + uint32 max_bitrate_configured, + uint32 min_bitrate_configured, + uint32 start_bitrate) + : congestion_control_back_off_(congestion_control_back_off), + max_bitrate_configured_(max_bitrate_configured), + min_bitrate_configured_(min_bitrate_configured), + bitrate_(start_bitrate), + default_tick_clock_(new base::DefaultTickClock()), + clock_(default_tick_clock_.get()) { + DCHECK_GT(congestion_control_back_off, 0.0f) << "Invalid config"; + DCHECK_LT(congestion_control_back_off, 1.0f) << "Invalid config"; + DCHECK_GE(max_bitrate_configured, min_bitrate_configured) << "Invalid config"; + DCHECK_GE(max_bitrate_configured, start_bitrate) << "Invalid config"; + DCHECK_GE(start_bitrate, min_bitrate_configured) << "Invalid config"; +} + +bool CongestionControl::OnAck(base::TimeDelta rtt, uint32* new_bitrate) { + base::TimeTicks now = clock_->NowTicks(); + + // First feedback? + if (time_last_increase_.is_null()) { + time_last_increase_ = now; + time_last_decrease_ = now; + return false; + } + // Are we at the max bitrate? + if (max_bitrate_configured_ == bitrate_) return false; + + // Make sure RTT is never less than 1 ms. + rtt = std::max(rtt, base::TimeDelta::FromMilliseconds(1)); + + base::TimeDelta elapsed_time = std::min(now - time_last_increase_, + base::TimeDelta::FromMilliseconds(kMaxElapsedTimeMs)); + base::TimeDelta change_interval = std::max(rtt, + base::TimeDelta::FromMilliseconds(kCongestionControlMinChangeIntervalMs)); + change_interval = std::min(change_interval, + base::TimeDelta::FromMilliseconds(kCongestionControlMaxChangeIntervalMs)); + + // Have enough time have passed? + if (elapsed_time < change_interval) return false; + + time_last_increase_ = now; + + // One packet per RTT multiplied by the elapsed time fraction. + // 1500 * 8 * (1000 / rtt_ms) * (elapsed_time_ms / 1000) => + // 1500 * 8 * elapsed_time_ms / rtt_ms. + uint32 bitrate_increase = (1500 * 8 * elapsed_time.InMilliseconds()) / + rtt.InMilliseconds(); + uint32 max_bitrate_increase = + kCongestionControlMaxBitrateIncreasePerMillisecond * + elapsed_time.InMilliseconds(); + bitrate_increase = std::min(max_bitrate_increase, bitrate_increase); + *new_bitrate = std::min(bitrate_increase + bitrate_, max_bitrate_configured_); + bitrate_ = *new_bitrate; + return true; +} + +bool CongestionControl::OnNack(base::TimeDelta rtt, uint32* new_bitrate) { + base::TimeTicks now = clock_->NowTicks(); + + // First feedback? + if (time_last_decrease_.is_null()) { + time_last_increase_ = now; + time_last_decrease_ = now; + return false; + } + base::TimeDelta elapsed_time = std::min(now - time_last_decrease_, + base::TimeDelta::FromMilliseconds(kMaxElapsedTimeMs)); + base::TimeDelta change_interval = std::max(rtt, + base::TimeDelta::FromMilliseconds(kCongestionControlMinChangeIntervalMs)); + change_interval = std::min(change_interval, + base::TimeDelta::FromMilliseconds(kCongestionControlMaxChangeIntervalMs)); + + // Have enough time have passed? + if (elapsed_time < change_interval) return false; + + time_last_decrease_ = now; + time_last_increase_ = now; + + *new_bitrate = std::max( + static_cast<uint32>(bitrate_ * congestion_control_back_off_), + min_bitrate_configured_); + + bitrate_ = *new_bitrate; + return true; +} + +} // namespace cast +} // namespace media |