1 /*
2  *  Copyright (c) 2019 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 "rtc_base/experiments/rate_control_settings.h"
12 
13 #include <inttypes.h>
14 #include <stdio.h>
15 
16 #include <string>
17 
18 #include "absl/strings/match.h"
19 #include "api/transport/field_trial_based_config.h"
20 #include "rtc_base/logging.h"
21 #include "rtc_base/numerics/safe_conversions.h"
22 
23 namespace webrtc {
24 
25 namespace {
26 
27 const int kDefaultAcceptedQueueMs = 350;
28 
29 const int kDefaultMinPushbackTargetBitrateBps = 30000;
30 
31 const char kCongestionWindowDefaultFieldTrialString[] =
32     "QueueSize:350,MinBitrate:30000,DropFrame:true";
33 
34 const char kUseBaseHeavyVp8Tl3RateAllocationFieldTrialName[] =
35     "WebRTC-UseBaseHeavyVP8TL3RateAllocation";
36 
37 const char* kVideoHysteresisFieldTrialname =
38     "WebRTC-SimulcastUpswitchHysteresisPercent";
39 const char* kScreenshareHysteresisFieldTrialname =
40     "WebRTC-SimulcastScreenshareUpswitchHysteresisPercent";
41 
IsEnabled(const WebRtcKeyValueConfig * const key_value_config,absl::string_view key)42 bool IsEnabled(const WebRtcKeyValueConfig* const key_value_config,
43                absl::string_view key) {
44   return absl::StartsWith(key_value_config->Lookup(key), "Enabled");
45 }
46 
ParseHysteresisFactor(const WebRtcKeyValueConfig * const key_value_config,absl::string_view key,double * output_value)47 void ParseHysteresisFactor(const WebRtcKeyValueConfig* const key_value_config,
48                            absl::string_view key,
49                            double* output_value) {
50   std::string group_name = key_value_config->Lookup(key);
51   int percent = 0;
52   if (!group_name.empty() && sscanf(group_name.c_str(), "%d", &percent) == 1 &&
53       percent >= 0) {
54     *output_value = 1.0 + (percent / 100.0);
55   }
56 }
57 
58 }  // namespace
59 
60 constexpr char CongestionWindowConfig::kKey[];
61 
Parser()62 std::unique_ptr<StructParametersParser> CongestionWindowConfig::Parser() {
63   return StructParametersParser::Create("QueueSize", &queue_size_ms,  //
64                                         "MinBitrate", &min_bitrate_bps,
65                                         "InitWin", &initial_data_window,
66                                         "DropFrame", &drop_frame_only);
67 }
68 
69 // static
Parse(absl::string_view config)70 CongestionWindowConfig CongestionWindowConfig::Parse(absl::string_view config) {
71   CongestionWindowConfig res;
72   res.Parser()->Parse(config);
73   return res;
74 }
75 
76 constexpr char VideoRateControlConfig::kKey[];
77 
Parser()78 std::unique_ptr<StructParametersParser> VideoRateControlConfig::Parser() {
79   // The empty comments ensures that each pair is on a separate line.
80   return StructParametersParser::Create(
81       "pacing_factor", &pacing_factor,                    //
82       "alr_probing", &alr_probing,                        //
83       "vp8_qp_max", &vp8_qp_max,                          //
84       "vp8_min_pixels", &vp8_min_pixels,                  //
85       "trust_vp8", &trust_vp8,                            //
86       "trust_vp9", &trust_vp9,                            //
87       "video_hysteresis", &video_hysteresis,              //
88       "screenshare_hysteresis", &screenshare_hysteresis,  //
89       "probe_max_allocation", &probe_max_allocation,      //
90       "bitrate_adjuster", &bitrate_adjuster,              //
91       "adjuster_use_headroom", &adjuster_use_headroom,    //
92       "vp8_s0_boost", &vp8_s0_boost,                      //
93       "vp8_base_heavy_tl3_alloc", &vp8_base_heavy_tl3_alloc);
94 }
95 
RateControlSettings(const WebRtcKeyValueConfig * const key_value_config)96 RateControlSettings::RateControlSettings(
97     const WebRtcKeyValueConfig* const key_value_config) {
98   std::string congestion_window_config =
99       key_value_config->Lookup(CongestionWindowConfig::kKey).empty()
100           ? kCongestionWindowDefaultFieldTrialString
101           : key_value_config->Lookup(CongestionWindowConfig::kKey);
102   congestion_window_config_ =
103       CongestionWindowConfig::Parse(congestion_window_config);
104   video_config_.vp8_base_heavy_tl3_alloc = IsEnabled(
105       key_value_config, kUseBaseHeavyVp8Tl3RateAllocationFieldTrialName);
106   ParseHysteresisFactor(key_value_config, kVideoHysteresisFieldTrialname,
107                         &video_config_.video_hysteresis);
108   ParseHysteresisFactor(key_value_config, kScreenshareHysteresisFieldTrialname,
109                         &video_config_.screenshare_hysteresis);
110   video_config_.Parser()->Parse(
111       key_value_config->Lookup(VideoRateControlConfig::kKey));
112 }
113 
114 RateControlSettings::~RateControlSettings() = default;
115 RateControlSettings::RateControlSettings(RateControlSettings&&) = default;
116 
ParseFromFieldTrials()117 RateControlSettings RateControlSettings::ParseFromFieldTrials() {
118   FieldTrialBasedConfig field_trial_config;
119   return RateControlSettings(&field_trial_config);
120 }
121 
ParseFromKeyValueConfig(const WebRtcKeyValueConfig * const key_value_config)122 RateControlSettings RateControlSettings::ParseFromKeyValueConfig(
123     const WebRtcKeyValueConfig* const key_value_config) {
124   FieldTrialBasedConfig field_trial_config;
125   return RateControlSettings(key_value_config ? key_value_config
126                                               : &field_trial_config);
127 }
128 
UseCongestionWindow() const129 bool RateControlSettings::UseCongestionWindow() const {
130   return static_cast<bool>(congestion_window_config_.queue_size_ms);
131 }
132 
GetCongestionWindowAdditionalTimeMs() const133 int64_t RateControlSettings::GetCongestionWindowAdditionalTimeMs() const {
134   return congestion_window_config_.queue_size_ms.value_or(
135       kDefaultAcceptedQueueMs);
136 }
137 
UseCongestionWindowPushback() const138 bool RateControlSettings::UseCongestionWindowPushback() const {
139   return congestion_window_config_.queue_size_ms &&
140          congestion_window_config_.min_bitrate_bps;
141 }
142 
UseCongestionWindowDropFrameOnly() const143 bool RateControlSettings::UseCongestionWindowDropFrameOnly() const {
144   return congestion_window_config_.drop_frame_only;
145 }
146 
CongestionWindowMinPushbackTargetBitrateBps() const147 uint32_t RateControlSettings::CongestionWindowMinPushbackTargetBitrateBps()
148     const {
149   return congestion_window_config_.min_bitrate_bps.value_or(
150       kDefaultMinPushbackTargetBitrateBps);
151 }
152 
153 absl::optional<DataSize>
CongestionWindowInitialDataWindow() const154 RateControlSettings::CongestionWindowInitialDataWindow() const {
155   return congestion_window_config_.initial_data_window;
156 }
157 
GetPacingFactor() const158 absl::optional<double> RateControlSettings::GetPacingFactor() const {
159   return video_config_.pacing_factor;
160 }
161 
UseAlrProbing() const162 bool RateControlSettings::UseAlrProbing() const {
163   return video_config_.alr_probing;
164 }
165 
LibvpxVp8QpMax() const166 absl::optional<int> RateControlSettings::LibvpxVp8QpMax() const {
167   if (video_config_.vp8_qp_max &&
168       (*video_config_.vp8_qp_max < 0 || *video_config_.vp8_qp_max > 63)) {
169     RTC_LOG(LS_WARNING) << "Unsupported vp8_qp_max_ value, ignored.";
170     return absl::nullopt;
171   }
172   return video_config_.vp8_qp_max;
173 }
174 
LibvpxVp8MinPixels() const175 absl::optional<int> RateControlSettings::LibvpxVp8MinPixels() const {
176   if (video_config_.vp8_min_pixels && *video_config_.vp8_min_pixels < 1) {
177     return absl::nullopt;
178   }
179   return video_config_.vp8_min_pixels;
180 }
181 
LibvpxVp8TrustedRateController() const182 bool RateControlSettings::LibvpxVp8TrustedRateController() const {
183   return video_config_.trust_vp8;
184 }
185 
Vp8BoostBaseLayerQuality() const186 bool RateControlSettings::Vp8BoostBaseLayerQuality() const {
187   return video_config_.vp8_s0_boost;
188 }
189 
LibvpxVp9TrustedRateController() const190 bool RateControlSettings::LibvpxVp9TrustedRateController() const {
191   return video_config_.trust_vp9;
192 }
193 
GetSimulcastHysteresisFactor(VideoCodecMode mode) const194 double RateControlSettings::GetSimulcastHysteresisFactor(
195     VideoCodecMode mode) const {
196   if (mode == VideoCodecMode::kScreensharing) {
197     return video_config_.screenshare_hysteresis;
198   }
199   return video_config_.video_hysteresis;
200 }
201 
GetSimulcastHysteresisFactor(VideoEncoderConfig::ContentType content_type) const202 double RateControlSettings::GetSimulcastHysteresisFactor(
203     VideoEncoderConfig::ContentType content_type) const {
204   if (content_type == VideoEncoderConfig::ContentType::kScreen) {
205     return video_config_.screenshare_hysteresis;
206   }
207   return video_config_.video_hysteresis;
208 }
209 
Vp8BaseHeavyTl3RateAllocation() const210 bool RateControlSettings::Vp8BaseHeavyTl3RateAllocation() const {
211   return video_config_.vp8_base_heavy_tl3_alloc;
212 }
213 
TriggerProbeOnMaxAllocatedBitrateChange() const214 bool RateControlSettings::TriggerProbeOnMaxAllocatedBitrateChange() const {
215   return video_config_.probe_max_allocation;
216 }
217 
UseEncoderBitrateAdjuster() const218 bool RateControlSettings::UseEncoderBitrateAdjuster() const {
219   return video_config_.bitrate_adjuster;
220 }
221 
BitrateAdjusterCanUseNetworkHeadroom() const222 bool RateControlSettings::BitrateAdjusterCanUseNetworkHeadroom() const {
223   return video_config_.adjuster_use_headroom;
224 }
225 
226 }  // namespace webrtc
227