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 = 250;
28 
29 const int kDefaultMinPushbackTargetBitrateBps = 30000;
30 
31 const char kUseBaseHeavyVp8Tl3RateAllocationFieldTrialName[] =
32     "WebRTC-UseBaseHeavyVP8TL3RateAllocation";
33 
34 const char* kVideoHysteresisFieldTrialname =
35     "WebRTC-SimulcastUpswitchHysteresisPercent";
36 const char* kScreenshareHysteresisFieldTrialname =
37     "WebRTC-SimulcastScreenshareUpswitchHysteresisPercent";
38 
IsEnabled(const WebRtcKeyValueConfig * const key_value_config,absl::string_view key)39 bool IsEnabled(const WebRtcKeyValueConfig* const key_value_config,
40                absl::string_view key) {
41   return absl::StartsWith(key_value_config->Lookup(key), "Enabled");
42 }
43 
ParseHysteresisFactor(const WebRtcKeyValueConfig * const key_value_config,absl::string_view key,double * output_value)44 void ParseHysteresisFactor(const WebRtcKeyValueConfig* const key_value_config,
45                            absl::string_view key,
46                            double* output_value) {
47   std::string group_name = key_value_config->Lookup(key);
48   int percent = 0;
49   if (!group_name.empty() && sscanf(group_name.c_str(), "%d", &percent) == 1 &&
50       percent >= 0) {
51     *output_value = 1.0 + (percent / 100.0);
52   }
53 }
54 
55 }  // namespace
56 
57 constexpr char CongestionWindowConfig::kKey[];
58 
Parser()59 std::unique_ptr<StructParametersParser> CongestionWindowConfig::Parser() {
60   return StructParametersParser::Create("QueueSize", &queue_size_ms,  //
61                                         "MinBitrate", &min_bitrate_bps,
62                                         "InitWin", &initial_data_window,
63                                         "DropFrame", &drop_frame_only);
64 }
65 
66 // static
Parse(absl::string_view config)67 CongestionWindowConfig CongestionWindowConfig::Parse(absl::string_view config) {
68   CongestionWindowConfig res;
69   res.Parser()->Parse(config);
70   return res;
71 }
72 
73 constexpr char VideoRateControlConfig::kKey[];
74 
Parser()75 std::unique_ptr<StructParametersParser> VideoRateControlConfig::Parser() {
76   // The empty comments ensures that each pair is on a separate line.
77   return StructParametersParser::Create(
78       "pacing_factor", &pacing_factor,                        //
79       "alr_probing", &alr_probing,                            //
80       "vp8_qp_max", &vp8_qp_max,                              //
81       "vp8_min_pixels", &vp8_min_pixels,                      //
82       "trust_vp8", &trust_vp8,                                //
83       "trust_vp9", &trust_vp9,                                //
84       "video_hysteresis", &video_hysteresis,                  //
85       "screenshare_hysteresis", &screenshare_hysteresis,      //
86       "probe_max_allocation", &probe_max_allocation,          //
87       "bitrate_adjuster", &bitrate_adjuster,                  //
88       "adjuster_use_headroom", &adjuster_use_headroom,        //
89       "vp8_s0_boost", &vp8_s0_boost,                          //
90       "vp8_base_heavy_tl3_alloc", &vp8_base_heavy_tl3_alloc,  //
91       "vp8_dynamic_rate", &vp8_dynamic_rate,                  //
92       "vp9_dynamic_rate", &vp9_dynamic_rate);
93 }
94 
RateControlSettings(const WebRtcKeyValueConfig * const key_value_config)95 RateControlSettings::RateControlSettings(
96     const WebRtcKeyValueConfig* const key_value_config)
97     : congestion_window_config_(CongestionWindowConfig::Parse(
98           key_value_config->Lookup(CongestionWindowConfig::kKey))) {
99   video_config_.vp8_base_heavy_tl3_alloc = IsEnabled(
100       key_value_config, kUseBaseHeavyVp8Tl3RateAllocationFieldTrialName);
101   ParseHysteresisFactor(key_value_config, kVideoHysteresisFieldTrialname,
102                         &video_config_.video_hysteresis);
103   ParseHysteresisFactor(key_value_config, kScreenshareHysteresisFieldTrialname,
104                         &video_config_.screenshare_hysteresis);
105   video_config_.Parser()->Parse(
106       key_value_config->Lookup(VideoRateControlConfig::kKey));
107 }
108 
109 RateControlSettings::~RateControlSettings() = default;
110 RateControlSettings::RateControlSettings(RateControlSettings&&) = default;
111 
ParseFromFieldTrials()112 RateControlSettings RateControlSettings::ParseFromFieldTrials() {
113   FieldTrialBasedConfig field_trial_config;
114   return RateControlSettings(&field_trial_config);
115 }
116 
ParseFromKeyValueConfig(const WebRtcKeyValueConfig * const key_value_config)117 RateControlSettings RateControlSettings::ParseFromKeyValueConfig(
118     const WebRtcKeyValueConfig* const key_value_config) {
119   FieldTrialBasedConfig field_trial_config;
120   return RateControlSettings(key_value_config ? key_value_config
121                                               : &field_trial_config);
122 }
123 
UseCongestionWindow() const124 bool RateControlSettings::UseCongestionWindow() const {
125   return static_cast<bool>(congestion_window_config_.queue_size_ms);
126 }
127 
GetCongestionWindowAdditionalTimeMs() const128 int64_t RateControlSettings::GetCongestionWindowAdditionalTimeMs() const {
129   return congestion_window_config_.queue_size_ms.value_or(
130       kDefaultAcceptedQueueMs);
131 }
132 
UseCongestionWindowPushback() const133 bool RateControlSettings::UseCongestionWindowPushback() const {
134   return congestion_window_config_.queue_size_ms &&
135          congestion_window_config_.min_bitrate_bps;
136 }
137 
UseCongestionWindowDropFrameOnly() const138 bool RateControlSettings::UseCongestionWindowDropFrameOnly() const {
139   return congestion_window_config_.drop_frame_only;
140 }
141 
CongestionWindowMinPushbackTargetBitrateBps() const142 uint32_t RateControlSettings::CongestionWindowMinPushbackTargetBitrateBps()
143     const {
144   return congestion_window_config_.min_bitrate_bps.value_or(
145       kDefaultMinPushbackTargetBitrateBps);
146 }
147 
148 absl::optional<DataSize>
CongestionWindowInitialDataWindow() const149 RateControlSettings::CongestionWindowInitialDataWindow() const {
150   return congestion_window_config_.initial_data_window;
151 }
152 
GetPacingFactor() const153 absl::optional<double> RateControlSettings::GetPacingFactor() const {
154   return video_config_.pacing_factor;
155 }
156 
UseAlrProbing() const157 bool RateControlSettings::UseAlrProbing() const {
158   return video_config_.alr_probing;
159 }
160 
LibvpxVp8QpMax() const161 absl::optional<int> RateControlSettings::LibvpxVp8QpMax() const {
162   if (video_config_.vp8_qp_max &&
163       (*video_config_.vp8_qp_max < 0 || *video_config_.vp8_qp_max > 63)) {
164     RTC_LOG(LS_WARNING) << "Unsupported vp8_qp_max_ value, ignored.";
165     return absl::nullopt;
166   }
167   return video_config_.vp8_qp_max;
168 }
169 
LibvpxVp8MinPixels() const170 absl::optional<int> RateControlSettings::LibvpxVp8MinPixels() const {
171   if (video_config_.vp8_min_pixels && *video_config_.vp8_min_pixels < 1) {
172     return absl::nullopt;
173   }
174   return video_config_.vp8_min_pixels;
175 }
176 
LibvpxVp8TrustedRateController() const177 bool RateControlSettings::LibvpxVp8TrustedRateController() const {
178   return video_config_.trust_vp8;
179 }
180 
Vp8BoostBaseLayerQuality() const181 bool RateControlSettings::Vp8BoostBaseLayerQuality() const {
182   return video_config_.vp8_s0_boost;
183 }
184 
Vp8DynamicRateSettings() const185 bool RateControlSettings::Vp8DynamicRateSettings() const {
186   return video_config_.vp8_dynamic_rate;
187 }
188 
LibvpxVp9TrustedRateController() const189 bool RateControlSettings::LibvpxVp9TrustedRateController() const {
190   return video_config_.trust_vp9;
191 }
192 
Vp9DynamicRateSettings() const193 bool RateControlSettings::Vp9DynamicRateSettings() const {
194   return video_config_.vp9_dynamic_rate;
195 }
196 
GetSimulcastHysteresisFactor(VideoCodecMode mode) const197 double RateControlSettings::GetSimulcastHysteresisFactor(
198     VideoCodecMode mode) const {
199   if (mode == VideoCodecMode::kScreensharing) {
200     return video_config_.screenshare_hysteresis;
201   }
202   return video_config_.video_hysteresis;
203 }
204 
GetSimulcastHysteresisFactor(VideoEncoderConfig::ContentType content_type) const205 double RateControlSettings::GetSimulcastHysteresisFactor(
206     VideoEncoderConfig::ContentType content_type) const {
207   if (content_type == VideoEncoderConfig::ContentType::kScreen) {
208     return video_config_.screenshare_hysteresis;
209   }
210   return video_config_.video_hysteresis;
211 }
212 
Vp8BaseHeavyTl3RateAllocation() const213 bool RateControlSettings::Vp8BaseHeavyTl3RateAllocation() const {
214   return video_config_.vp8_base_heavy_tl3_alloc;
215 }
216 
TriggerProbeOnMaxAllocatedBitrateChange() const217 bool RateControlSettings::TriggerProbeOnMaxAllocatedBitrateChange() const {
218   return video_config_.probe_max_allocation;
219 }
220 
UseEncoderBitrateAdjuster() const221 bool RateControlSettings::UseEncoderBitrateAdjuster() const {
222   return video_config_.bitrate_adjuster;
223 }
224 
BitrateAdjusterCanUseNetworkHeadroom() const225 bool RateControlSettings::BitrateAdjusterCanUseNetworkHeadroom() const {
226   return video_config_.adjuster_use_headroom;
227 }
228 
229 }  // namespace webrtc
230