OLD | NEW |
1 // Copyright 2013 The Chromium Authors. All rights reserved. | 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 | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
| 5 // The purpose of this file is determine what bitrate to use for mirroring. |
| 6 // Ideally this should be as much as possible, without causing any frames to |
| 7 // arrive late. |
| 8 |
| 9 // The current algorithm is to measure how much bandwidth we've been using |
| 10 // recently. We also keep track of how much data has been queued up for sending |
| 11 // in a virtual "buffer" (this virtual buffer represents all the buffers between |
| 12 // the sender and the receiver, including retransmissions and so forth.) |
| 13 // If we estimate that our virtual buffer is mostly empty, we try to use |
| 14 // more bandwidth than our recent usage, otherwise we use less. |
| 15 |
5 #include "media/cast/congestion_control/congestion_control.h" | 16 #include "media/cast/congestion_control/congestion_control.h" |
6 | 17 |
7 #include "base/logging.h" | 18 #include "base/logging.h" |
8 #include "media/cast/cast_config.h" | 19 #include "media/cast/cast_config.h" |
9 #include "media/cast/cast_defines.h" | 20 #include "media/cast/cast_defines.h" |
10 | 21 |
11 namespace media { | 22 namespace media { |
12 namespace cast { | 23 namespace cast { |
13 | 24 |
14 static const int64 kCongestionControlMinChangeIntervalMs = 10; | 25 // This means that we *try* to keep our buffer 90% empty. |
15 static const int64 kCongestionControlMaxChangeIntervalMs = 100; | 26 // If it is less full, we increase the bandwidth, if it is more |
| 27 // we decrease the bandwidth. Making this smaller makes the |
| 28 // congestion control more aggressive. |
| 29 static const double kTargetEmptyBufferFraction = 0.9; |
16 | 30 |
17 // At 10 ms RTT TCP Reno would ramp 1500 * 8 * 100 = 1200 Kbit/s. | 31 // This is the size of our history in frames. Larger values makes the |
18 // NACK is sent after a maximum of 10 ms. | 32 // congestion control adapt slower. |
19 static const int kCongestionControlMaxBitrateIncreasePerMillisecond = 1200; | 33 static const size_t kHistorySize = 100; |
20 | 34 |
21 static const int64 kMaxElapsedTimeMs = kCongestionControlMaxChangeIntervalMs; | 35 CongestionControl::FrameStats::FrameStats() : frame_size(0) { |
| 36 } |
22 | 37 |
23 CongestionControl::CongestionControl(base::TickClock* clock, | 38 CongestionControl::CongestionControl(base::TickClock* clock, |
24 float congestion_control_back_off, | |
25 uint32 max_bitrate_configured, | 39 uint32 max_bitrate_configured, |
26 uint32 min_bitrate_configured, | 40 uint32 min_bitrate_configured, |
27 uint32 start_bitrate) | 41 size_t max_unacked_frames) |
28 : clock_(clock), | 42 : clock_(clock), |
29 congestion_control_back_off_(congestion_control_back_off), | |
30 max_bitrate_configured_(max_bitrate_configured), | 43 max_bitrate_configured_(max_bitrate_configured), |
31 min_bitrate_configured_(min_bitrate_configured), | 44 min_bitrate_configured_(min_bitrate_configured), |
32 bitrate_(start_bitrate) { | 45 last_frame_stats_(static_cast<uint32>(-1)), |
33 DCHECK_GT(congestion_control_back_off, 0.0f) << "Invalid config"; | 46 last_acked_frame_(static_cast<uint32>(-1)), |
34 DCHECK_LT(congestion_control_back_off, 1.0f) << "Invalid config"; | 47 last_encoded_frame_(static_cast<uint32>(-1)), |
| 48 history_size_(max_unacked_frames + kHistorySize), |
| 49 acked_bits_in_history_(0) { |
35 DCHECK_GE(max_bitrate_configured, min_bitrate_configured) << "Invalid config"; | 50 DCHECK_GE(max_bitrate_configured, min_bitrate_configured) << "Invalid config"; |
36 DCHECK_GE(max_bitrate_configured, start_bitrate) << "Invalid config"; | 51 frame_stats_.resize(2); |
37 DCHECK_GE(start_bitrate, min_bitrate_configured) << "Invalid config"; | 52 base::TimeTicks now = clock->NowTicks(); |
| 53 frame_stats_[0].ack_time = now; |
| 54 frame_stats_[0].sent_time = now; |
| 55 frame_stats_[1].ack_time = now; |
| 56 DCHECK(!frame_stats_[0].ack_time.is_null()); |
38 } | 57 } |
39 | 58 |
40 CongestionControl::~CongestionControl() {} | 59 CongestionControl::~CongestionControl() {} |
41 | 60 |
42 bool CongestionControl::OnAck(base::TimeDelta rtt, uint32* new_bitrate) { | 61 void CongestionControl::UpdateRtt(base::TimeDelta rtt) { |
43 base::TimeTicks now = clock_->NowTicks(); | 62 rtt_ = base::TimeDelta::FromSecondsD( |
44 | 63 (rtt_.InSecondsF() * 7 + rtt.InSecondsF()) / 8); |
45 // First feedback? | |
46 if (time_last_increase_.is_null()) { | |
47 time_last_increase_ = now; | |
48 time_last_decrease_ = now; | |
49 return false; | |
50 } | |
51 // Are we at the max bitrate? | |
52 if (max_bitrate_configured_ == bitrate_) | |
53 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 = | |
59 std::min(now - time_last_increase_, | |
60 base::TimeDelta::FromMilliseconds(kMaxElapsedTimeMs)); | |
61 base::TimeDelta change_interval = std::max( | |
62 rtt, | |
63 base::TimeDelta::FromMilliseconds(kCongestionControlMinChangeIntervalMs)); | |
64 change_interval = std::min( | |
65 change_interval, | |
66 base::TimeDelta::FromMilliseconds(kCongestionControlMaxChangeIntervalMs)); | |
67 | |
68 // Have enough time have passed? | |
69 if (elapsed_time < change_interval) | |
70 return false; | |
71 | |
72 time_last_increase_ = now; | |
73 | |
74 // One packet per RTT multiplied by the elapsed time fraction. | |
75 // 1500 * 8 * (1000 / rtt_ms) * (elapsed_time_ms / 1000) => | |
76 // 1500 * 8 * elapsed_time_ms / rtt_ms. | |
77 uint32 bitrate_increase = | |
78 (1500 * 8 * elapsed_time.InMilliseconds()) / rtt.InMilliseconds(); | |
79 uint32 max_bitrate_increase = | |
80 kCongestionControlMaxBitrateIncreasePerMillisecond * | |
81 elapsed_time.InMilliseconds(); | |
82 bitrate_increase = std::min(max_bitrate_increase, bitrate_increase); | |
83 *new_bitrate = std::min(bitrate_increase + bitrate_, max_bitrate_configured_); | |
84 bitrate_ = *new_bitrate; | |
85 return true; | |
86 } | 64 } |
87 | 65 |
88 bool CongestionControl::OnNack(base::TimeDelta rtt, uint32* new_bitrate) { | 66 // Calculate how much "dead air" there is between two frames. |
89 base::TimeTicks now = clock_->NowTicks(); | 67 base::TimeDelta CongestionControl::DeadTime(const FrameStats& a, |
| 68 const FrameStats& b) { |
| 69 if (b.sent_time > a.ack_time) { |
| 70 return b.sent_time - a.ack_time; |
| 71 } else { |
| 72 return base::TimeDelta(); |
| 73 } |
| 74 } |
90 | 75 |
91 // First feedback? | 76 double CongestionControl::CalculateSafeBitrate() { |
92 if (time_last_decrease_.is_null()) { | 77 double transmit_time = |
93 time_last_increase_ = now; | 78 (GetFrameStats(last_acked_frame_)->ack_time - |
94 time_last_decrease_ = now; | 79 frame_stats_.front().sent_time - dead_time_in_history_).InSecondsF(); |
95 return false; | 80 |
| 81 if (acked_bits_in_history_ == 0 || transmit_time <= 0.0) { |
| 82 return min_bitrate_configured_; |
96 } | 83 } |
97 base::TimeDelta elapsed_time = | 84 return acked_bits_in_history_ / std::max(transmit_time, 1E-3); |
98 std::min(now - time_last_decrease_, | 85 } |
99 base::TimeDelta::FromMilliseconds(kMaxElapsedTimeMs)); | |
100 base::TimeDelta change_interval = std::max( | |
101 rtt, | |
102 base::TimeDelta::FromMilliseconds(kCongestionControlMinChangeIntervalMs)); | |
103 change_interval = std::min( | |
104 change_interval, | |
105 base::TimeDelta::FromMilliseconds(kCongestionControlMaxChangeIntervalMs)); | |
106 | 86 |
107 // Have enough time have passed? | 87 CongestionControl::FrameStats* CongestionControl::GetFrameStats( |
108 if (elapsed_time < change_interval) | 88 uint32 frame_id) { |
109 return false; | 89 int32 offset = static_cast<int32>(frame_id - last_frame_stats_); |
| 90 DCHECK_LT(offset, static_cast<int32>(kHistorySize)); |
| 91 if (offset > 0) { |
| 92 frame_stats_.resize(frame_stats_.size() + offset); |
| 93 last_frame_stats_ += offset; |
| 94 offset = 0; |
| 95 } |
| 96 while (frame_stats_.size() > history_size_) { |
| 97 DCHECK_GT(frame_stats_.size(), 1UL); |
| 98 DCHECK(!frame_stats_[0].ack_time.is_null()); |
| 99 acked_bits_in_history_ -= frame_stats_[0].frame_size; |
| 100 dead_time_in_history_ -= DeadTime(frame_stats_[0], frame_stats_[1]); |
| 101 DCHECK_GE(acked_bits_in_history_, 0UL); |
| 102 VLOG(2) << "DT: " << dead_time_in_history_.InSecondsF(); |
| 103 DCHECK_GE(dead_time_in_history_.InSecondsF(), 0.0); |
| 104 frame_stats_.pop_front(); |
| 105 } |
| 106 offset += frame_stats_.size() - 1; |
| 107 if (offset < 0 || offset >= static_cast<int32>(frame_stats_.size())) { |
| 108 return NULL; |
| 109 } |
| 110 return &frame_stats_[offset]; |
| 111 } |
110 | 112 |
111 time_last_decrease_ = now; | 113 void CongestionControl::AckFrame(uint32 frame_id, base::TimeTicks when) { |
112 time_last_increase_ = now; | 114 FrameStats* frame_stats = GetFrameStats(last_acked_frame_); |
| 115 while (IsNewerFrameId(frame_id, last_acked_frame_)) { |
| 116 FrameStats* last_frame_stats = frame_stats; |
| 117 last_acked_frame_++; |
| 118 frame_stats = GetFrameStats(last_acked_frame_); |
| 119 DCHECK(frame_stats); |
| 120 frame_stats->ack_time = when; |
| 121 acked_bits_in_history_ += frame_stats->frame_size; |
| 122 dead_time_in_history_ += DeadTime(*last_frame_stats, *frame_stats); |
| 123 } |
| 124 } |
113 | 125 |
114 *new_bitrate = | 126 void CongestionControl::SendFrameToTransport(uint32 frame_id, |
115 std::max(static_cast<uint32>(bitrate_ * congestion_control_back_off_), | 127 size_t frame_size, |
116 min_bitrate_configured_); | 128 base::TimeTicks when) { |
| 129 last_encoded_frame_ = frame_id; |
| 130 FrameStats* frame_stats = GetFrameStats(frame_id); |
| 131 DCHECK(frame_stats); |
| 132 frame_stats->frame_size = frame_size; |
| 133 frame_stats->sent_time = when; |
| 134 } |
117 | 135 |
118 bitrate_ = *new_bitrate; | 136 base::TimeTicks CongestionControl::EstimatedAckTime(uint32 frame_id, |
119 return true; | 137 double bitrate) { |
| 138 FrameStats* frame_stats = GetFrameStats(frame_id); |
| 139 DCHECK(frame_stats); |
| 140 if (frame_stats->ack_time.is_null()) { |
| 141 DCHECK(frame_stats->frame_size) << "frame_id: " << frame_id; |
| 142 base::TimeTicks ret = EstimatedSendingTime(frame_id, bitrate); |
| 143 ret += base::TimeDelta::FromSecondsD(frame_stats->frame_size / bitrate); |
| 144 ret += rtt_; |
| 145 base::TimeTicks now = clock_->NowTicks(); |
| 146 if (ret < now) { |
| 147 // This is a little counter-intuitive, but it seems to work. |
| 148 // Basically, when we estimate that the ACK should have already happened, |
| 149 // we figure out how long ago it should have happened and guess that the |
| 150 // ACK will happen half of that time in the future. This will cause some |
| 151 // over-estimation when acks are late, which is actually what we want. |
| 152 return now + (now - ret) / 2; |
| 153 } else { |
| 154 return ret; |
| 155 } |
| 156 } else { |
| 157 return frame_stats->ack_time; |
| 158 } |
| 159 } |
| 160 |
| 161 base::TimeTicks CongestionControl::EstimatedSendingTime(uint32 frame_id, |
| 162 double bitrate) { |
| 163 FrameStats* frame_stats = GetFrameStats(frame_id); |
| 164 DCHECK(frame_stats); |
| 165 base::TimeTicks ret = EstimatedAckTime(frame_id - 1, bitrate) - rtt_; |
| 166 if (frame_stats->sent_time.is_null()) { |
| 167 // Not sent yet, but we can't start sending it in the past. |
| 168 return std::max(ret, clock_->NowTicks()); |
| 169 } else { |
| 170 return std::max(ret, frame_stats->sent_time); |
| 171 } |
| 172 } |
| 173 |
| 174 uint32 CongestionControl::GetBitrate(base::TimeTicks playout_time, |
| 175 base::TimeDelta playout_delay) { |
| 176 double safe_bitrate = CalculateSafeBitrate(); |
| 177 // Estimate when we might start sending the next frame. |
| 178 base::TimeDelta time_to_catch_up = |
| 179 playout_time - |
| 180 EstimatedSendingTime(last_encoded_frame_ + 1, safe_bitrate); |
| 181 |
| 182 double empty_buffer_fraction = |
| 183 time_to_catch_up.InSecondsF() / playout_delay.InSecondsF(); |
| 184 empty_buffer_fraction = std::min(empty_buffer_fraction, 1.0); |
| 185 empty_buffer_fraction = std::max(empty_buffer_fraction, 0.0); |
| 186 |
| 187 uint32 bits_per_second = static_cast<uint32>( |
| 188 safe_bitrate * empty_buffer_fraction / kTargetEmptyBufferFraction); |
| 189 VLOG(3) << " FBR:" << (bits_per_second / 1E6) |
| 190 << " EBF:" << empty_buffer_fraction |
| 191 << " SBR:" << (safe_bitrate / 1E6); |
| 192 bits_per_second = std::max(bits_per_second, min_bitrate_configured_); |
| 193 bits_per_second = std::min(bits_per_second, max_bitrate_configured_); |
| 194 return bits_per_second; |
120 } | 195 } |
121 | 196 |
122 } // namespace cast | 197 } // namespace cast |
123 } // namespace media | 198 } // namespace media |
OLD | NEW |