1 /*
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 
11 #include "modules/pacing/alr_detector.h"
12 
13 #include <string>
14 
15 #include "rtc_base/checks.h"
16 #include "rtc_base/format_macros.h"
17 #include "rtc_base/logging.h"
18 #include "rtc_base/timeutils.h"
19 #include "system_wrappers/include/field_trial.h"
20 
21 namespace webrtc {
22 
23 const char AlrDetector::kScreenshareProbingBweExperimentName[] =
24     "WebRTC-ProbingScreenshareBwe";
25 const char AlrDetector::kStrictPacingAndProbingExperimentName[] =
26     "WebRTC-StrictPacingAndProbing";
27 const char kDefaultProbingScreenshareBweSettings[] = "1.0,2875,80,40,-60,3";
28 
AlrDetector()29 AlrDetector::AlrDetector()
30     : bandwidth_usage_percent_(kDefaultAlrBandwidthUsagePercent),
31       alr_start_budget_level_percent_(kDefaultAlrStartBudgetLevelPercent),
32       alr_stop_budget_level_percent_(kDefaultAlrStopBudgetLevelPercent),
33       alr_budget_(0, true) {
34   RTC_CHECK(
35       field_trial::FindFullName(kStrictPacingAndProbingExperimentName)
36           .empty() ||
37       field_trial::FindFullName(kScreenshareProbingBweExperimentName).empty());
38   rtc::Optional<AlrExperimentSettings> experiment_settings =
39       ParseAlrSettingsFromFieldTrial(kScreenshareProbingBweExperimentName);
40   if (!experiment_settings) {
41     experiment_settings =
42         ParseAlrSettingsFromFieldTrial(kStrictPacingAndProbingExperimentName);
43   }
44   if (experiment_settings) {
45     alr_stop_budget_level_percent_ =
46         experiment_settings->alr_stop_budget_level_percent;
47     alr_start_budget_level_percent_ =
48         experiment_settings->alr_start_budget_level_percent;
49     bandwidth_usage_percent_ = experiment_settings->alr_bandwidth_usage_percent;
50   }
51 }
52 
~AlrDetector()53 AlrDetector::~AlrDetector() {}
54 
OnBytesSent(size_t bytes_sent,int64_t delta_time_ms)55 void AlrDetector::OnBytesSent(size_t bytes_sent, int64_t delta_time_ms) {
56   alr_budget_.UseBudget(bytes_sent);
57   alr_budget_.IncreaseBudget(delta_time_ms);
58 
59   if (alr_budget_.budget_level_percent() > alr_start_budget_level_percent_ &&
60       !alr_started_time_ms_) {
61     alr_started_time_ms_.emplace(rtc::TimeMillis());
62   } else if (alr_budget_.budget_level_percent() <
63                  alr_stop_budget_level_percent_ &&
64              alr_started_time_ms_) {
65     alr_started_time_ms_.reset();
66   }
67 }
68 
SetEstimatedBitrate(int bitrate_bps)69 void AlrDetector::SetEstimatedBitrate(int bitrate_bps) {
70   RTC_DCHECK(bitrate_bps);
71   const auto target_rate_kbps = int64_t{bitrate_bps} *
72                                 bandwidth_usage_percent_ / (1000 * 100);
73   alr_budget_.set_target_rate_kbps(rtc::dchecked_cast<int>(target_rate_kbps));
74 }
75 
GetApplicationLimitedRegionStartTime() const76 rtc::Optional<int64_t> AlrDetector::GetApplicationLimitedRegionStartTime()
77     const {
78   return alr_started_time_ms_;
79 }
80 
81 rtc::Optional<AlrDetector::AlrExperimentSettings>
ParseAlrSettingsFromFieldTrial(const char * experiment_name)82 AlrDetector::ParseAlrSettingsFromFieldTrial(const char* experiment_name) {
83   rtc::Optional<AlrExperimentSettings> ret;
84   std::string group_name = field_trial::FindFullName(experiment_name);
85 
86   const std::string kIgnoredSuffix = "_Dogfood";
87   std::string::size_type suffix_pos = group_name.rfind(kIgnoredSuffix);
88   if (suffix_pos != std::string::npos &&
89       suffix_pos == group_name.length() - kIgnoredSuffix.length()) {
90     group_name.resize(group_name.length() - kIgnoredSuffix.length());
91   }
92 
93   if (experiment_name == kScreenshareProbingBweExperimentName) {
94     // This experiment is now default-on with fixed settings.
95     // TODO(sprang): Remove this kill-switch and clean up experiment code.
96     if (group_name != "Disabled") {
97       group_name = kDefaultProbingScreenshareBweSettings;
98     }
99   }
100 
101   if (group_name.empty())
102     return ret;
103 
104   AlrExperimentSettings settings;
105   if (sscanf(group_name.c_str(), "%f,%" PRId64 ",%d,%d,%d,%d",
106              &settings.pacing_factor, &settings.max_paced_queue_time,
107              &settings.alr_bandwidth_usage_percent,
108              &settings.alr_start_budget_level_percent,
109              &settings.alr_stop_budget_level_percent,
110              &settings.group_id) == 6) {
111     ret.emplace(settings);
112     RTC_LOG(LS_INFO) << "Using ALR experiment settings: "
113                         "pacing factor: "
114                      << settings.pacing_factor << ", max pacer queue length: "
115                      << settings.max_paced_queue_time
116                      << ", ALR start bandwidth usage percent: "
117                      << settings.alr_bandwidth_usage_percent
118                      << ", ALR end budget level percent: "
119                      << settings.alr_start_budget_level_percent
120                      << ", ALR end budget level percent: "
121                      << settings.alr_stop_budget_level_percent
122                      << ", ALR experiment group ID: " << settings.group_id;
123   } else {
124     RTC_LOG(LS_INFO) << "Failed to parse ALR experiment: " << experiment_name;
125   }
126 
127   return ret;
128 }
129 
130 }  // namespace webrtc
131