blob: 8c5934d23803a589d6b058976cecb99cc72472fa [file] [log] [blame]
philipel233c4ba2016-08-01 08:49:04 -07001/*
2 * Copyright (c) 2016 The WebRTC project authors. All Rights Reserved.
3 *
4 * Use of this source code is governed by a BSD-style license
5 * that can be found in the LICENSE file in the root of the source
6 * tree. An additional intellectual property rights grant can be found
7 * in the file PATENTS. All contributing project authors may
8 * be found in the AUTHORS file in the root of the source tree.
9 */
10
Mirko Bonadei92ea95e2017-09-15 06:47:31 +020011#include "modules/congestion_controller/probe_bitrate_estimator.h"
philipel233c4ba2016-08-01 08:49:04 -070012
13#include <algorithm>
14
Elad Alon4a87e1c2017-10-03 16:11:34 +020015#include "logging/rtc_event_log/events/rtc_event_probe_result_failure.h"
16#include "logging/rtc_event_log/events/rtc_event_probe_result_success.h"
Mirko Bonadei92ea95e2017-09-15 06:47:31 +020017#include "logging/rtc_event_log/rtc_event_log.h"
18#include "rtc_base/checks.h"
19#include "rtc_base/logging.h"
Elad Alon4a87e1c2017-10-03 16:11:34 +020020#include "rtc_base/ptr_util.h"
philipel233c4ba2016-08-01 08:49:04 -070021
22namespace {
philipelb5feb2e2017-03-09 07:01:58 -080023// The minumum number of probes we need to receive feedback about in percent
24// in order to have a valid estimate.
25constexpr int kMinReceivedProbesPercent = 80;
26
27// The minumum number of bytes we need to receive feedback about in percent
28// in order to have a valid estimate.
29constexpr int kMinReceivedBytesPercent = 80;
philipel233c4ba2016-08-01 08:49:04 -070030
terelius37647302017-06-27 07:50:31 -070031// The maximum |receive rate| / |send rate| ratio for a valid estimate.
32constexpr float kMaxValidRatio = 2.0f;
33
34// The minimum |receive rate| / |send rate| ratio assuming that the link is
35// not saturated, i.e. we assume that we will receive at least
36// kMinRatioForUnsaturatedLink * |send rate| if |send rate| is less than the
37// link capacity.
38constexpr float kMinRatioForUnsaturatedLink = 0.9f;
39
40// The target utilization of the link. If we know true link capacity
41// we'd like to send at 95% of that rate.
42constexpr float kTargetUtilizationFraction = 0.95f;
Irfan Sherifff99a9de2016-08-23 14:23:03 -070043
44// The maximum time period over which the cluster history is retained.
45// This is also the maximum time period beyond which a probing burst is not
46// expected to last.
47constexpr int kMaxClusterHistoryMs = 1000;
48
49// The maximum time interval between first and the last probe on a cluster
50// on the sender side as well as the receive side.
51constexpr int kMaxProbeIntervalMs = 1000;
52} // namespace
philipel233c4ba2016-08-01 08:49:04 -070053
54namespace webrtc {
55
philipelf4238f92017-03-28 04:18:02 -070056ProbeBitrateEstimator::ProbeBitrateEstimator(RtcEventLog* event_log)
57 : event_log_(event_log) {}
philipel233c4ba2016-08-01 08:49:04 -070058
nisse76e62b02017-05-31 02:24:52 -070059ProbeBitrateEstimator::~ProbeBitrateEstimator() = default;
60
Irfan Sherifff99a9de2016-08-23 14:23:03 -070061int ProbeBitrateEstimator::HandleProbeAndEstimateBitrate(
elad.alonf9490002017-03-06 05:32:21 -080062 const PacketFeedback& packet_feedback) {
63 int cluster_id = packet_feedback.pacing_info.probe_cluster_id;
philipel8aadd502017-02-23 02:56:13 -080064 RTC_DCHECK_NE(cluster_id, PacedPacketInfo::kNotAProbe);
Irfan Sherifff99a9de2016-08-23 14:23:03 -070065
elad.alonf9490002017-03-06 05:32:21 -080066 EraseOldClusters(packet_feedback.arrival_time_ms - kMaxClusterHistoryMs);
philipel233c4ba2016-08-01 08:49:04 -070067
elad.alonf9490002017-03-06 05:32:21 -080068 int payload_size_bits = packet_feedback.payload_size * 8;
philipel8aadd502017-02-23 02:56:13 -080069 AggregatedCluster* cluster = &clusters_[cluster_id];
philipel0561bdf2016-08-24 03:43:53 -070070
elad.alonf9490002017-03-06 05:32:21 -080071 if (packet_feedback.send_time_ms < cluster->first_send_ms) {
72 cluster->first_send_ms = packet_feedback.send_time_ms;
philipel0561bdf2016-08-24 03:43:53 -070073 }
elad.alonf9490002017-03-06 05:32:21 -080074 if (packet_feedback.send_time_ms > cluster->last_send_ms) {
75 cluster->last_send_ms = packet_feedback.send_time_ms;
philipel0561bdf2016-08-24 03:43:53 -070076 cluster->size_last_send = payload_size_bits;
77 }
elad.alonf9490002017-03-06 05:32:21 -080078 if (packet_feedback.arrival_time_ms < cluster->first_receive_ms) {
79 cluster->first_receive_ms = packet_feedback.arrival_time_ms;
philipel0561bdf2016-08-24 03:43:53 -070080 cluster->size_first_receive = payload_size_bits;
81 }
elad.alonf9490002017-03-06 05:32:21 -080082 if (packet_feedback.arrival_time_ms > cluster->last_receive_ms) {
83 cluster->last_receive_ms = packet_feedback.arrival_time_ms;
philipel0561bdf2016-08-24 03:43:53 -070084 }
85 cluster->size_total += payload_size_bits;
86 cluster->num_probes += 1;
philipel233c4ba2016-08-01 08:49:04 -070087
philipelb5feb2e2017-03-09 07:01:58 -080088 RTC_DCHECK_GT(packet_feedback.pacing_info.probe_cluster_min_probes, 0);
89 RTC_DCHECK_GT(packet_feedback.pacing_info.probe_cluster_min_bytes, 0);
90
91 int min_probes = packet_feedback.pacing_info.probe_cluster_min_probes *
92 kMinReceivedProbesPercent / 100;
93 int min_bytes = packet_feedback.pacing_info.probe_cluster_min_bytes *
94 kMinReceivedBytesPercent / 100;
95 if (cluster->num_probes < min_probes || cluster->size_total < min_bytes * 8)
Irfan Sherifff99a9de2016-08-23 14:23:03 -070096 return -1;
philipel233c4ba2016-08-01 08:49:04 -070097
philipelbf8a2c92016-08-10 19:00:39 +020098 float send_interval_ms = cluster->last_send_ms - cluster->first_send_ms;
99 float receive_interval_ms =
philipel233c4ba2016-08-01 08:49:04 -0700100 cluster->last_receive_ms - cluster->first_receive_ms;
101
Irfan Sherifff99a9de2016-08-23 14:23:03 -0700102 if (send_interval_ms <= 0 || send_interval_ms > kMaxProbeIntervalMs ||
103 receive_interval_ms <= 0 || receive_interval_ms > kMaxProbeIntervalMs) {
Mirko Bonadei675513b2017-11-09 11:09:25 +0100104 RTC_LOG(LS_INFO) << "Probing unsuccessful, invalid send/receive interval"
105 << " [cluster id: " << cluster_id
106 << "] [send interval: " << send_interval_ms << " ms]"
107 << " [receive interval: " << receive_interval_ms << " ms]";
philipelf4238f92017-03-28 04:18:02 -0700108 if (event_log_) {
Elad Alon4a87e1c2017-10-03 16:11:34 +0200109 event_log_->Log(rtc::MakeUnique<RtcEventProbeResultFailure>(
110 cluster_id, ProbeFailureReason::kInvalidSendReceiveInterval));
philipelf4238f92017-03-28 04:18:02 -0700111 }
Irfan Sherifff99a9de2016-08-23 14:23:03 -0700112 return -1;
philipel233c4ba2016-08-01 08:49:04 -0700113 }
philipel0561bdf2016-08-24 03:43:53 -0700114 // Since the |send_interval_ms| does not include the time it takes to actually
115 // send the last packet the size of the last sent packet should not be
116 // included when calculating the send bitrate.
117 RTC_DCHECK_GT(cluster->size_total, cluster->size_last_send);
118 float send_size = cluster->size_total - cluster->size_last_send;
119 float send_bps = send_size / send_interval_ms * 1000;
120
121 // Since the |receive_interval_ms| does not include the time it takes to
122 // actually receive the first packet the size of the first received packet
123 // should not be included when calculating the receive bitrate.
124 RTC_DCHECK_GT(cluster->size_total, cluster->size_first_receive);
125 float receive_size = cluster->size_total - cluster->size_first_receive;
126 float receive_bps = receive_size / receive_interval_ms * 1000;
127
philipel233c4ba2016-08-01 08:49:04 -0700128 float ratio = receive_bps / send_bps;
terelius37647302017-06-27 07:50:31 -0700129 if (ratio > kMaxValidRatio) {
Mirko Bonadei675513b2017-11-09 11:09:25 +0100130 RTC_LOG(LS_INFO) << "Probing unsuccessful, receive/send ratio too high"
131 << " [cluster id: " << cluster_id
132 << "] [send: " << send_size << " bytes / "
133 << send_interval_ms << " ms = " << send_bps / 1000
134 << " kb/s]"
135 << " [receive: " << receive_size << " bytes / "
136 << receive_interval_ms << " ms = " << receive_bps / 1000
137 << " kb/s]"
138 << " [ratio: " << receive_bps / 1000 << " / "
139 << send_bps / 1000 << " = " << ratio
140 << " > kMaxValidRatio (" << kMaxValidRatio << ")]";
Elad Alon4a87e1c2017-10-03 16:11:34 +0200141 if (event_log_) {
142 event_log_->Log(rtc::MakeUnique<RtcEventProbeResultFailure>(
143 cluster_id, ProbeFailureReason::kInvalidSendReceiveRatio));
144 }
Irfan Sherifff99a9de2016-08-23 14:23:03 -0700145 return -1;
philipel233c4ba2016-08-01 08:49:04 -0700146 }
Mirko Bonadei675513b2017-11-09 11:09:25 +0100147 RTC_LOG(LS_INFO) << "Probing successful"
148 << " [cluster id: " << cluster_id << "] [send: " << send_size
149 << " bytes / " << send_interval_ms
150 << " ms = " << send_bps / 1000 << " kb/s]"
151 << " [receive: " << receive_size << " bytes / "
152 << receive_interval_ms << " ms = " << receive_bps / 1000
153 << " kb/s]";
michaelt8490f8a2017-04-20 10:10:10 -0700154
philipelf4238f92017-03-28 04:18:02 -0700155 float res = std::min(send_bps, receive_bps);
terelius37647302017-06-27 07:50:31 -0700156 // If we're receiving at significantly lower bitrate than we were sending at,
157 // it suggests that we've found the true capacity of the link. In this case,
158 // set the target bitrate slightly lower to not immediately overuse.
159 if (receive_bps < kMinRatioForUnsaturatedLink * send_bps) {
160 RTC_DCHECK_GT(send_bps, receive_bps);
161 res = kTargetUtilizationFraction * receive_bps;
162 }
Elad Alon4a87e1c2017-10-03 16:11:34 +0200163 if (event_log_) {
164 event_log_->Log(
165 rtc::MakeUnique<RtcEventProbeResultSuccess>(cluster_id, res));
166 }
terelius91047e52017-06-19 06:07:30 -0700167 estimated_bitrate_bps_ = rtc::Optional<int>(res);
michaelt8490f8a2017-04-20 10:10:10 -0700168 return *estimated_bitrate_bps_;
169}
170
171rtc::Optional<int>
172ProbeBitrateEstimator::FetchAndResetLastEstimatedBitrateBps() {
173 rtc::Optional<int> estimated_bitrate_bps = estimated_bitrate_bps_;
174 estimated_bitrate_bps_.reset();
175 return estimated_bitrate_bps;
Irfan Sherifff99a9de2016-08-23 14:23:03 -0700176}
philipel233c4ba2016-08-01 08:49:04 -0700177
Irfan Sherifff99a9de2016-08-23 14:23:03 -0700178void ProbeBitrateEstimator::EraseOldClusters(int64_t timestamp_ms) {
179 for (auto it = clusters_.begin(); it != clusters_.end();) {
180 if (it->second.last_receive_ms < timestamp_ms) {
181 it = clusters_.erase(it);
182 } else {
183 ++it;
184 }
185 }
philipel233c4ba2016-08-01 08:49:04 -0700186}
187} // namespace webrtc