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