• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2013 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
5 #include "media/cast/congestion_control/congestion_control.h"
6 
7 #include "base/logging.h"
8 #include "media/cast/cast_config.h"
9 #include "media/cast/cast_defines.h"
10 
11 namespace media {
12 namespace cast {
13 
14 static const int64 kCongestionControlMinChangeIntervalMs = 10;
15 static const int64 kCongestionControlMaxChangeIntervalMs = 100;
16 
17 // At 10 ms RTT TCP Reno would ramp 1500 * 8 * 100  = 1200 Kbit/s.
18 // NACK is sent after a maximum of 10 ms.
19 static const int kCongestionControlMaxBitrateIncreasePerMillisecond = 1200;
20 
21 static const int64 kMaxElapsedTimeMs = kCongestionControlMaxChangeIntervalMs;
22 
CongestionControl(base::TickClock * clock,float congestion_control_back_off,uint32 max_bitrate_configured,uint32 min_bitrate_configured,uint32 start_bitrate)23 CongestionControl::CongestionControl(base::TickClock* clock,
24                                      float congestion_control_back_off,
25                                      uint32 max_bitrate_configured,
26                                      uint32 min_bitrate_configured,
27                                      uint32 start_bitrate)
28     : clock_(clock),
29       congestion_control_back_off_(congestion_control_back_off),
30       max_bitrate_configured_(max_bitrate_configured),
31       min_bitrate_configured_(min_bitrate_configured),
32       bitrate_(start_bitrate) {
33   DCHECK_GT(congestion_control_back_off, 0.0f) << "Invalid config";
34   DCHECK_LT(congestion_control_back_off, 1.0f) << "Invalid config";
35   DCHECK_GE(max_bitrate_configured, min_bitrate_configured) << "Invalid config";
36   DCHECK_GE(max_bitrate_configured, start_bitrate) << "Invalid config";
37   DCHECK_GE(start_bitrate, min_bitrate_configured) << "Invalid config";
38 }
39 
~CongestionControl()40 CongestionControl::~CongestionControl() {
41 }
42 
OnAck(base::TimeDelta rtt,uint32 * new_bitrate)43 bool CongestionControl::OnAck(base::TimeDelta rtt, uint32* new_bitrate) {
44   base::TimeTicks now = clock_->NowTicks();
45 
46   // First feedback?
47   if (time_last_increase_.is_null()) {
48     time_last_increase_ = now;
49     time_last_decrease_ = now;
50     return false;
51   }
52   // Are we at the max bitrate?
53   if (max_bitrate_configured_ == bitrate_)  return false;
54 
55   // Make sure RTT is never less than 1 ms.
56   rtt = std::max(rtt, base::TimeDelta::FromMilliseconds(1));
57 
58   base::TimeDelta elapsed_time = std::min(now - time_last_increase_,
59       base::TimeDelta::FromMilliseconds(kMaxElapsedTimeMs));
60   base::TimeDelta change_interval = std::max(rtt,
61       base::TimeDelta::FromMilliseconds(kCongestionControlMinChangeIntervalMs));
62   change_interval = std::min(change_interval,
63       base::TimeDelta::FromMilliseconds(kCongestionControlMaxChangeIntervalMs));
64 
65   // Have enough time have passed?
66   if (elapsed_time < change_interval)  return false;
67 
68   time_last_increase_ = now;
69 
70   // One packet per RTT multiplied by the elapsed time fraction.
71   // 1500 * 8 * (1000 / rtt_ms) * (elapsed_time_ms / 1000) =>
72   // 1500 * 8 * elapsed_time_ms / rtt_ms.
73   uint32 bitrate_increase = (1500 * 8 * elapsed_time.InMilliseconds()) /
74      rtt.InMilliseconds();
75   uint32 max_bitrate_increase =
76       kCongestionControlMaxBitrateIncreasePerMillisecond *
77           elapsed_time.InMilliseconds();
78   bitrate_increase = std::min(max_bitrate_increase, bitrate_increase);
79   *new_bitrate = std::min(bitrate_increase + bitrate_, max_bitrate_configured_);
80   bitrate_ = *new_bitrate;
81   return true;
82 }
83 
OnNack(base::TimeDelta rtt,uint32 * new_bitrate)84 bool CongestionControl::OnNack(base::TimeDelta rtt, uint32* new_bitrate) {
85   base::TimeTicks now = clock_->NowTicks();
86 
87   // First feedback?
88   if (time_last_decrease_.is_null()) {
89     time_last_increase_ = now;
90     time_last_decrease_ = now;
91     return false;
92   }
93   base::TimeDelta elapsed_time = std::min(now - time_last_decrease_,
94       base::TimeDelta::FromMilliseconds(kMaxElapsedTimeMs));
95   base::TimeDelta change_interval = std::max(rtt,
96       base::TimeDelta::FromMilliseconds(kCongestionControlMinChangeIntervalMs));
97   change_interval = std::min(change_interval,
98       base::TimeDelta::FromMilliseconds(kCongestionControlMaxChangeIntervalMs));
99 
100   // Have enough time have passed?
101   if (elapsed_time < change_interval)  return false;
102 
103   time_last_decrease_ = now;
104   time_last_increase_ = now;
105 
106   *new_bitrate = std::max(
107       static_cast<uint32>(bitrate_ * congestion_control_back_off_),
108       min_bitrate_configured_);
109 
110   bitrate_ = *new_bitrate;
111   return true;
112 }
113 
114 }  // namespace cast
115 }  // namespace media
116