Skip to content

Commit b5cba85

Browse files
Erik SprångWebRTC LUCI CQ
Erik Språng
authored and
WebRTC LUCI CQ
committed
Add support for time-varying constraints in DegradedCall.
The fake network configs are now specified using just two field trials: WebRTC-FakeNetworkSendConfig and WebRTC-FakeNetworkReceiveConfig. Both of them have the following parameters from BuiltInNetworkBehaviorConfig: * queue_length_packets // Queue length in number of packets. * queue_delay_ms // Delay in addition to capacity induced delay. * delay_standard_deviation_ms // Standard deviation of the extra delay. * link_capacity_kbps // Link capacity in kbps. * loss_percent // Random packet loss. * allow_reordering // If packets are allowed to be reordered. * avg_burst_loss_length // The average length of a burst of lost packets. * packet_overhead // Additional bytes to add to packet size. * codel_active_queue_management // Enable CoDel active queue management. Plus: * duration // For how long to use this config before progressing. Example: WebRTC-FakeNetworkSendConfig/queue_delay_ms:66|1,loss_percent:1|0,link_capacity_kbps:200|10000,queue_length_packets:10|100,duration:15s|45s/ This creates two configs: 1. For 15s, apply 66ms delay, 1% loss, 200kbps bandwidth, 10 packet queue size 2. For 45s, apply 1ms delay, 0% loss, 10Mbps bandwidth, 100 packets queue size (then repeat) Bug: webrtc:13655 Change-Id: I0524f572de480731df4d414724203772182c628b Reviewed-on: https://webrtc-review.googlesource.com/c/src/+/251043 Reviewed-by: Stefan Holmer <[email protected]> Commit-Queue: Erik Språng <[email protected]> Cr-Commit-Position: refs/heads/main@{#35952}
1 parent 27c1452 commit b5cba85

File tree

3 files changed

+154
-44
lines changed

3 files changed

+154
-44
lines changed

call/call_factory.cc

Lines changed: 94 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -15,26 +15,34 @@
1515
#include <memory>
1616
#include <string>
1717
#include <utility>
18+
#include <vector>
1819

1920
#include "absl/types/optional.h"
2021
#include "api/test/simulated_network.h"
22+
#include "api/units/time_delta.h"
2123
#include "call/call.h"
2224
#include "call/degraded_call.h"
2325
#include "call/rtp_transport_config.h"
2426
#include "rtc_base/checks.h"
25-
#include "system_wrappers/include/field_trial.h"
27+
#include "rtc_base/experiments/field_trial_list.h"
28+
#include "rtc_base/experiments/field_trial_parser.h"
2629

2730
namespace webrtc {
2831
namespace {
29-
bool ParseConfigParam(std::string exp_name, int* field) {
30-
std::string group = field_trial::FindFullName(exp_name);
32+
using TimeScopedNetworkConfig = DegradedCall::TimeScopedNetworkConfig;
33+
34+
bool ParseConfigParam(const WebRtcKeyValueConfig& trials,
35+
absl::string_view exp_name,
36+
int* field) {
37+
std::string group = trials.Lookup(exp_name);
3138
if (group.empty())
3239
return false;
3340

3441
return (sscanf(group.c_str(), "%d", field) == 1);
3542
}
3643

37-
absl::optional<webrtc::BuiltInNetworkBehaviorConfig> ParseDegradationConfig(
44+
absl::optional<TimeScopedNetworkConfig> ParseDegradationConfig(
45+
const WebRtcKeyValueConfig& trials,
3846
bool send) {
3947
std::string exp_prefix = "WebRTCFakeNetwork";
4048
if (send) {
@@ -43,33 +51,92 @@ absl::optional<webrtc::BuiltInNetworkBehaviorConfig> ParseDegradationConfig(
4351
exp_prefix += "Receive";
4452
}
4553

46-
webrtc::BuiltInNetworkBehaviorConfig config;
54+
TimeScopedNetworkConfig config;
4755
bool configured = false;
4856
configured |=
49-
ParseConfigParam(exp_prefix + "DelayMs", &config.queue_delay_ms);
50-
configured |= ParseConfigParam(exp_prefix + "DelayStdDevMs",
57+
ParseConfigParam(trials, exp_prefix + "DelayMs", &config.queue_delay_ms);
58+
configured |= ParseConfigParam(trials, exp_prefix + "DelayStdDevMs",
5159
&config.delay_standard_deviation_ms);
5260
int queue_length = 0;
53-
if (ParseConfigParam(exp_prefix + "QueueLength", &queue_length)) {
61+
if (ParseConfigParam(trials, exp_prefix + "QueueLength", &queue_length)) {
5462
RTC_CHECK_GE(queue_length, 0);
5563
config.queue_length_packets = queue_length;
5664
configured = true;
5765
}
58-
configured |=
59-
ParseConfigParam(exp_prefix + "CapacityKbps", &config.link_capacity_kbps);
60-
configured |=
61-
ParseConfigParam(exp_prefix + "LossPercent", &config.loss_percent);
66+
configured |= ParseConfigParam(trials, exp_prefix + "CapacityKbps",
67+
&config.link_capacity_kbps);
68+
configured |= ParseConfigParam(trials, exp_prefix + "LossPercent",
69+
&config.loss_percent);
6270
int allow_reordering = 0;
63-
if (ParseConfigParam(exp_prefix + "AllowReordering", &allow_reordering)) {
71+
if (ParseConfigParam(trials, exp_prefix + "AllowReordering",
72+
&allow_reordering)) {
6473
config.allow_reordering = true;
6574
configured = true;
6675
}
67-
configured |= ParseConfigParam(exp_prefix + "AvgBurstLossLength",
76+
configured |= ParseConfigParam(trials, exp_prefix + "AvgBurstLossLength",
6877
&config.avg_burst_loss_length);
69-
return configured
70-
? absl::optional<webrtc::BuiltInNetworkBehaviorConfig>(config)
71-
: absl::nullopt;
78+
return configured ? absl::optional<TimeScopedNetworkConfig>(config)
79+
: absl::nullopt;
7280
}
81+
82+
std::vector<TimeScopedNetworkConfig> GetNetworkConfigs(
83+
const WebRtcKeyValueConfig& trials,
84+
bool send) {
85+
FieldTrialStructList<TimeScopedNetworkConfig> trials_list(
86+
{FieldTrialStructMember("queue_length_packets",
87+
[](TimeScopedNetworkConfig* p) {
88+
// FieldTrialParser does not natively support
89+
// size_t type, so use this ugly cast as
90+
// workaround.
91+
return reinterpret_cast<unsigned*>(
92+
&p->queue_length_packets);
93+
}),
94+
FieldTrialStructMember(
95+
"queue_delay_ms",
96+
[](TimeScopedNetworkConfig* p) { return &p->queue_delay_ms; }),
97+
FieldTrialStructMember("delay_standard_deviation_ms",
98+
[](TimeScopedNetworkConfig* p) {
99+
return &p->delay_standard_deviation_ms;
100+
}),
101+
FieldTrialStructMember(
102+
"link_capacity_kbps",
103+
[](TimeScopedNetworkConfig* p) { return &p->link_capacity_kbps; }),
104+
FieldTrialStructMember(
105+
"loss_percent",
106+
[](TimeScopedNetworkConfig* p) { return &p->loss_percent; }),
107+
FieldTrialStructMember(
108+
"allow_reordering",
109+
[](TimeScopedNetworkConfig* p) { return &p->allow_reordering; }),
110+
FieldTrialStructMember("avg_burst_loss_length",
111+
[](TimeScopedNetworkConfig* p) {
112+
return &p->avg_burst_loss_length;
113+
}),
114+
FieldTrialStructMember(
115+
"packet_overhead",
116+
[](TimeScopedNetworkConfig* p) { return &p->packet_overhead; }),
117+
FieldTrialStructMember("codel_active_queue_management",
118+
[](TimeScopedNetworkConfig* p) {
119+
return &p->codel_active_queue_management;
120+
}),
121+
FieldTrialStructMember(
122+
"duration",
123+
[](TimeScopedNetworkConfig* p) { return &p->duration; })},
124+
{});
125+
ParseFieldTrial({&trials_list},
126+
trials.Lookup(send ? "WebRTC-FakeNetworkSendConfig"
127+
: "WebRTC-FakeNetworkReceiveConfig"));
128+
std::vector<TimeScopedNetworkConfig> configs = trials_list.Get();
129+
if (configs.empty()) {
130+
// Try legacy fallback trials.
131+
absl::optional<DegradedCall::TimeScopedNetworkConfig> fallback_config =
132+
ParseDegradationConfig(trials, send);
133+
if (fallback_config.has_value()) {
134+
configs.push_back(*fallback_config);
135+
}
136+
}
137+
return configs;
138+
}
139+
73140
} // namespace
74141

75142
CallFactory::CallFactory() {
@@ -78,14 +145,18 @@ CallFactory::CallFactory() {
78145

79146
Call* CallFactory::CreateCall(const Call::Config& config) {
80147
RTC_DCHECK_RUN_ON(&call_thread_);
81-
absl::optional<webrtc::BuiltInNetworkBehaviorConfig> send_degradation_config =
82-
ParseDegradationConfig(true);
83-
absl::optional<webrtc::BuiltInNetworkBehaviorConfig>
84-
receive_degradation_config = ParseDegradationConfig(false);
148+
RTC_DCHECK(config.trials);
149+
150+
std::vector<DegradedCall::TimeScopedNetworkConfig> send_degradation_configs =
151+
GetNetworkConfigs(*config.trials, /*send=*/true);
152+
std::vector<DegradedCall::TimeScopedNetworkConfig>
153+
receive_degradation_configs =
154+
GetNetworkConfigs(*config.trials, /*send=*/false);
85155

86156
RtpTransportConfig transportConfig = config.ExtractTransportConfig();
87157

88-
if (send_degradation_config || receive_degradation_config) {
158+
if (!send_degradation_configs.empty() ||
159+
!receive_degradation_configs.empty()) {
89160
return new DegradedCall(
90161
std::unique_ptr<Call>(Call::Create(
91162
config, Clock::GetRealTimeClock(),
@@ -94,7 +165,7 @@ Call* CallFactory::CreateCall(const Call::Config& config) {
94165
config.rtp_transport_controller_send_factory->Create(
95166
transportConfig, Clock::GetRealTimeClock(),
96167
ProcessThread::Create("PacerThread")))),
97-
send_degradation_config, receive_degradation_config,
168+
send_degradation_configs, receive_degradation_configs,
98169
config.task_queue_factory);
99170
}
100171

call/degraded_call.cc

Lines changed: 42 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -127,35 +127,47 @@ bool DegradedCall::FakeNetworkPipeTransportAdapter::SendRtcp(
127127

128128
DegradedCall::DegradedCall(
129129
std::unique_ptr<Call> call,
130-
absl::optional<BuiltInNetworkBehaviorConfig> send_config,
131-
absl::optional<BuiltInNetworkBehaviorConfig> receive_config,
130+
const std::vector<TimeScopedNetworkConfig>& send_configs,
131+
const std::vector<TimeScopedNetworkConfig>& receive_configs,
132132
TaskQueueFactory* task_queue_factory)
133133
: clock_(Clock::GetRealTimeClock()),
134134
call_(std::move(call)),
135135
task_queue_factory_(task_queue_factory),
136-
send_config_(send_config),
136+
send_config_index_(0),
137+
send_configs_(send_configs),
137138
send_simulated_network_(nullptr),
138-
receive_config_(receive_config) {
139-
if (receive_config_) {
140-
auto network = std::make_unique<SimulatedNetwork>(*receive_config_);
139+
receive_config_index_(0),
140+
receive_configs_(receive_configs) {
141+
if (!receive_configs_.empty()) {
142+
auto network = std::make_unique<SimulatedNetwork>(receive_configs_[0]);
141143
receive_simulated_network_ = network.get();
142144
receive_pipe_ =
143145
std::make_unique<webrtc::FakeNetworkPipe>(clock_, std::move(network));
144146
receive_pipe_->SetReceiver(call_->Receiver());
147+
if (receive_configs_.size() > 1) {
148+
call_->network_thread()->PostDelayedTask(
149+
ToQueuedTask(task_safety_, [this] { UpdateReceiveNetworkConfig(); }),
150+
receive_configs_[0].duration.ms());
151+
}
145152
}
146-
if (send_config_) {
147-
auto network = std::make_unique<SimulatedNetwork>(*send_config_);
153+
if (!send_configs_.empty()) {
154+
auto network = std::make_unique<SimulatedNetwork>(send_configs_[0]);
148155
send_simulated_network_ = network.get();
149156
send_pipe_ = std::make_unique<FakeNetworkPipeOnTaskQueue>(
150157
task_queue_factory_, clock_, std::move(network));
158+
if (send_configs_.size() > 1) {
159+
call_->network_thread()->PostDelayedTask(
160+
ToQueuedTask(task_safety_, [this] { UpdateSendNetworkConfig(); }),
161+
send_configs_[0].duration.ms());
162+
}
151163
}
152164
}
153165

154166
DegradedCall::~DegradedCall() = default;
155167

156168
AudioSendStream* DegradedCall::CreateAudioSendStream(
157169
const AudioSendStream::Config& config) {
158-
if (send_config_) {
170+
if (!send_configs_.empty()) {
159171
auto transport_adapter = std::make_unique<FakeNetworkPipeTransportAdapter>(
160172
send_pipe_.get(), call_.get(), clock_, config.send_transport);
161173
AudioSendStream::Config degrade_config = config;
@@ -189,7 +201,7 @@ VideoSendStream* DegradedCall::CreateVideoSendStream(
189201
VideoSendStream::Config config,
190202
VideoEncoderConfig encoder_config) {
191203
std::unique_ptr<FakeNetworkPipeTransportAdapter> transport_adapter;
192-
if (send_config_) {
204+
if (!send_configs_.empty()) {
193205
transport_adapter = std::make_unique<FakeNetworkPipeTransportAdapter>(
194206
send_pipe_.get(), call_.get(), clock_, config.send_transport);
195207
config.send_transport = transport_adapter.get();
@@ -207,7 +219,7 @@ VideoSendStream* DegradedCall::CreateVideoSendStream(
207219
VideoEncoderConfig encoder_config,
208220
std::unique_ptr<FecController> fec_controller) {
209221
std::unique_ptr<FakeNetworkPipeTransportAdapter> transport_adapter;
210-
if (send_config_) {
222+
if (!send_configs_.empty()) {
211223
transport_adapter = std::make_unique<FakeNetworkPipeTransportAdapter>(
212224
send_pipe_.get(), call_.get(), clock_, config.send_transport);
213225
config.send_transport = transport_adapter.get();
@@ -251,7 +263,7 @@ void DegradedCall::AddAdaptationResource(
251263
}
252264

253265
PacketReceiver* DegradedCall::Receiver() {
254-
if (receive_config_) {
266+
if (!receive_configs_.empty()) {
255267
return this;
256268
}
257269
return call_->Receiver();
@@ -299,7 +311,7 @@ void DegradedCall::OnUpdateSyncGroup(AudioReceiveStream& stream,
299311
}
300312

301313
void DegradedCall::OnSentPacket(const rtc::SentPacket& sent_packet) {
302-
if (send_config_) {
314+
if (!send_configs_.empty()) {
303315
// If we have a degraded send-transport, we have already notified call
304316
// about the supposed network send time. Discard the actual network send
305317
// time in order to properly fool the BWE.
@@ -325,4 +337,21 @@ PacketReceiver::DeliveryStatus DegradedCall::DeliverPacket(
325337
receive_pipe_->Process();
326338
return status;
327339
}
340+
341+
void DegradedCall::UpdateSendNetworkConfig() {
342+
send_config_index_ = (send_config_index_ + 1) % send_configs_.size();
343+
send_simulated_network_->SetConfig(send_configs_[send_config_index_]);
344+
call_->network_thread()->PostDelayedTask(
345+
ToQueuedTask(task_safety_, [this] { UpdateSendNetworkConfig(); }),
346+
send_configs_[send_config_index_].duration.ms());
347+
}
348+
349+
void DegradedCall::UpdateReceiveNetworkConfig() {
350+
receive_config_index_ = (receive_config_index_ + 1) % receive_configs_.size();
351+
receive_simulated_network_->SetConfig(
352+
receive_configs_[receive_config_index_]);
353+
call_->network_thread()->PostDelayedTask(
354+
ToQueuedTask(task_safety_, [this] { UpdateReceiveNetworkConfig(); }),
355+
receive_configs_[receive_config_index_].duration.ms());
356+
}
328357
} // namespace webrtc

call/degraded_call.h

Lines changed: 18 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717
#include <map>
1818
#include <memory>
1919
#include <string>
20+
#include <vector>
2021

2122
#include "absl/types/optional.h"
2223
#include "api/call/transport.h"
@@ -38,15 +39,20 @@
3839
#include "rtc_base/copy_on_write_buffer.h"
3940
#include "rtc_base/network/sent_packet.h"
4041
#include "rtc_base/task_queue.h"
42+
#include "rtc_base/task_utils/pending_task_safety_flag.h"
4143
#include "system_wrappers/include/clock.h"
4244

4345
namespace webrtc {
4446
class DegradedCall : public Call, private PacketReceiver {
4547
public:
48+
struct TimeScopedNetworkConfig : public BuiltInNetworkBehaviorConfig {
49+
TimeDelta duration = TimeDelta::PlusInfinity();
50+
};
51+
4652
explicit DegradedCall(
4753
std::unique_ptr<Call> call,
48-
absl::optional<BuiltInNetworkBehaviorConfig> send_config,
49-
absl::optional<BuiltInNetworkBehaviorConfig> receive_config,
54+
const std::vector<TimeScopedNetworkConfig>& send_configs,
55+
const std::vector<TimeScopedNetworkConfig>& receive_configs,
5056
TaskQueueFactory* task_queue_factory);
5157
~DegradedCall() override;
5258

@@ -157,22 +163,26 @@ class DegradedCall : public Call, private PacketReceiver {
157163
Transport* const real_transport_;
158164
};
159165

160-
Clock* const clock_;
161-
const std::unique_ptr<Call> call_;
162-
TaskQueueFactory* const task_queue_factory_;
163-
164166
void SetClientBitratePreferences(
165167
const webrtc::BitrateSettings& preferences) override {}
168+
void UpdateSendNetworkConfig();
169+
void UpdateReceiveNetworkConfig();
166170

167-
const absl::optional<BuiltInNetworkBehaviorConfig> send_config_;
171+
Clock* const clock_;
172+
const std::unique_ptr<Call> call_;
173+
ScopedTaskSafety task_safety_;
174+
TaskQueueFactory* const task_queue_factory_;
175+
size_t send_config_index_;
176+
const std::vector<TimeScopedNetworkConfig> send_configs_;
168177
SimulatedNetwork* send_simulated_network_;
169178
std::unique_ptr<FakeNetworkPipeOnTaskQueue> send_pipe_;
170179
std::map<AudioSendStream*, std::unique_ptr<FakeNetworkPipeTransportAdapter>>
171180
audio_send_transport_adapters_;
172181
std::map<VideoSendStream*, std::unique_ptr<FakeNetworkPipeTransportAdapter>>
173182
video_send_transport_adapters_;
174183

175-
const absl::optional<BuiltInNetworkBehaviorConfig> receive_config_;
184+
size_t receive_config_index_;
185+
const std::vector<TimeScopedNetworkConfig> receive_configs_;
176186
SimulatedNetwork* receive_simulated_network_;
177187
std::unique_ptr<FakeNetworkPipe> receive_pipe_;
178188
};

0 commit comments

Comments
 (0)