diff --git a/call/call_factory.cc b/call/call_factory.cc index aeb3cbdaa7..a3079eb7b2 100644 --- a/call/call_factory.cc +++ b/call/call_factory.cc @@ -15,26 +15,34 @@ #include #include #include +#include #include "absl/types/optional.h" #include "api/test/simulated_network.h" +#include "api/units/time_delta.h" #include "call/call.h" #include "call/degraded_call.h" #include "call/rtp_transport_config.h" #include "rtc_base/checks.h" -#include "system_wrappers/include/field_trial.h" +#include "rtc_base/experiments/field_trial_list.h" +#include "rtc_base/experiments/field_trial_parser.h" namespace webrtc { namespace { -bool ParseConfigParam(std::string exp_name, int* field) { - std::string group = field_trial::FindFullName(exp_name); +using TimeScopedNetworkConfig = DegradedCall::TimeScopedNetworkConfig; + +bool ParseConfigParam(const WebRtcKeyValueConfig& trials, + absl::string_view exp_name, + int* field) { + std::string group = trials.Lookup(exp_name); if (group.empty()) return false; return (sscanf(group.c_str(), "%d", field) == 1); } -absl::optional ParseDegradationConfig( +absl::optional ParseDegradationConfig( + const WebRtcKeyValueConfig& trials, bool send) { std::string exp_prefix = "WebRTCFakeNetwork"; if (send) { @@ -43,33 +51,92 @@ absl::optional ParseDegradationConfig( exp_prefix += "Receive"; } - webrtc::BuiltInNetworkBehaviorConfig config; + TimeScopedNetworkConfig config; bool configured = false; configured |= - ParseConfigParam(exp_prefix + "DelayMs", &config.queue_delay_ms); - configured |= ParseConfigParam(exp_prefix + "DelayStdDevMs", + ParseConfigParam(trials, exp_prefix + "DelayMs", &config.queue_delay_ms); + configured |= ParseConfigParam(trials, exp_prefix + "DelayStdDevMs", &config.delay_standard_deviation_ms); int queue_length = 0; - if (ParseConfigParam(exp_prefix + "QueueLength", &queue_length)) { + if (ParseConfigParam(trials, exp_prefix + "QueueLength", &queue_length)) { RTC_CHECK_GE(queue_length, 0); config.queue_length_packets = queue_length; configured = true; } - configured |= - ParseConfigParam(exp_prefix + "CapacityKbps", &config.link_capacity_kbps); - configured |= - ParseConfigParam(exp_prefix + "LossPercent", &config.loss_percent); + configured |= ParseConfigParam(trials, exp_prefix + "CapacityKbps", + &config.link_capacity_kbps); + configured |= ParseConfigParam(trials, exp_prefix + "LossPercent", + &config.loss_percent); int allow_reordering = 0; - if (ParseConfigParam(exp_prefix + "AllowReordering", &allow_reordering)) { + if (ParseConfigParam(trials, exp_prefix + "AllowReordering", + &allow_reordering)) { config.allow_reordering = true; configured = true; } - configured |= ParseConfigParam(exp_prefix + "AvgBurstLossLength", + configured |= ParseConfigParam(trials, exp_prefix + "AvgBurstLossLength", &config.avg_burst_loss_length); - return configured - ? absl::optional(config) - : absl::nullopt; + return configured ? absl::optional(config) + : absl::nullopt; } + +std::vector GetNetworkConfigs( + const WebRtcKeyValueConfig& trials, + bool send) { + FieldTrialStructList trials_list( + {FieldTrialStructMember("queue_length_packets", + [](TimeScopedNetworkConfig* p) { + // FieldTrialParser does not natively support + // size_t type, so use this ugly cast as + // workaround. + return reinterpret_cast( + &p->queue_length_packets); + }), + FieldTrialStructMember( + "queue_delay_ms", + [](TimeScopedNetworkConfig* p) { return &p->queue_delay_ms; }), + FieldTrialStructMember("delay_standard_deviation_ms", + [](TimeScopedNetworkConfig* p) { + return &p->delay_standard_deviation_ms; + }), + FieldTrialStructMember( + "link_capacity_kbps", + [](TimeScopedNetworkConfig* p) { return &p->link_capacity_kbps; }), + FieldTrialStructMember( + "loss_percent", + [](TimeScopedNetworkConfig* p) { return &p->loss_percent; }), + FieldTrialStructMember( + "allow_reordering", + [](TimeScopedNetworkConfig* p) { return &p->allow_reordering; }), + FieldTrialStructMember("avg_burst_loss_length", + [](TimeScopedNetworkConfig* p) { + return &p->avg_burst_loss_length; + }), + FieldTrialStructMember( + "packet_overhead", + [](TimeScopedNetworkConfig* p) { return &p->packet_overhead; }), + FieldTrialStructMember("codel_active_queue_management", + [](TimeScopedNetworkConfig* p) { + return &p->codel_active_queue_management; + }), + FieldTrialStructMember( + "duration", + [](TimeScopedNetworkConfig* p) { return &p->duration; })}, + {}); + ParseFieldTrial({&trials_list}, + trials.Lookup(send ? "WebRTC-FakeNetworkSendConfig" + : "WebRTC-FakeNetworkReceiveConfig")); + std::vector configs = trials_list.Get(); + if (configs.empty()) { + // Try legacy fallback trials. + absl::optional fallback_config = + ParseDegradationConfig(trials, send); + if (fallback_config.has_value()) { + configs.push_back(*fallback_config); + } + } + return configs; +} + } // namespace CallFactory::CallFactory() { @@ -78,14 +145,18 @@ CallFactory::CallFactory() { Call* CallFactory::CreateCall(const Call::Config& config) { RTC_DCHECK_RUN_ON(&call_thread_); - absl::optional send_degradation_config = - ParseDegradationConfig(true); - absl::optional - receive_degradation_config = ParseDegradationConfig(false); + RTC_DCHECK(config.trials); + + std::vector send_degradation_configs = + GetNetworkConfigs(*config.trials, /*send=*/true); + std::vector + receive_degradation_configs = + GetNetworkConfigs(*config.trials, /*send=*/false); RtpTransportConfig transportConfig = config.ExtractTransportConfig(); - if (send_degradation_config || receive_degradation_config) { + if (!send_degradation_configs.empty() || + !receive_degradation_configs.empty()) { return new DegradedCall( std::unique_ptr(Call::Create( config, Clock::GetRealTimeClock(), @@ -94,7 +165,7 @@ Call* CallFactory::CreateCall(const Call::Config& config) { config.rtp_transport_controller_send_factory->Create( transportConfig, Clock::GetRealTimeClock(), ProcessThread::Create("PacerThread")))), - send_degradation_config, receive_degradation_config, + send_degradation_configs, receive_degradation_configs, config.task_queue_factory); } diff --git a/call/degraded_call.cc b/call/degraded_call.cc index 2370bc0b38..1eb2275d20 100644 --- a/call/degraded_call.cc +++ b/call/degraded_call.cc @@ -127,27 +127,39 @@ bool DegradedCall::FakeNetworkPipeTransportAdapter::SendRtcp( DegradedCall::DegradedCall( std::unique_ptr call, - absl::optional send_config, - absl::optional receive_config, + const std::vector& send_configs, + const std::vector& receive_configs, TaskQueueFactory* task_queue_factory) : clock_(Clock::GetRealTimeClock()), call_(std::move(call)), task_queue_factory_(task_queue_factory), - send_config_(send_config), + send_config_index_(0), + send_configs_(send_configs), send_simulated_network_(nullptr), - receive_config_(receive_config) { - if (receive_config_) { - auto network = std::make_unique(*receive_config_); + receive_config_index_(0), + receive_configs_(receive_configs) { + if (!receive_configs_.empty()) { + auto network = std::make_unique(receive_configs_[0]); receive_simulated_network_ = network.get(); receive_pipe_ = std::make_unique(clock_, std::move(network)); receive_pipe_->SetReceiver(call_->Receiver()); + if (receive_configs_.size() > 1) { + call_->network_thread()->PostDelayedTask( + ToQueuedTask(task_safety_, [this] { UpdateReceiveNetworkConfig(); }), + receive_configs_[0].duration.ms()); + } } - if (send_config_) { - auto network = std::make_unique(*send_config_); + if (!send_configs_.empty()) { + auto network = std::make_unique(send_configs_[0]); send_simulated_network_ = network.get(); send_pipe_ = std::make_unique( task_queue_factory_, clock_, std::move(network)); + if (send_configs_.size() > 1) { + call_->network_thread()->PostDelayedTask( + ToQueuedTask(task_safety_, [this] { UpdateSendNetworkConfig(); }), + send_configs_[0].duration.ms()); + } } } @@ -155,7 +167,7 @@ DegradedCall::~DegradedCall() = default; AudioSendStream* DegradedCall::CreateAudioSendStream( const AudioSendStream::Config& config) { - if (send_config_) { + if (!send_configs_.empty()) { auto transport_adapter = std::make_unique( send_pipe_.get(), call_.get(), clock_, config.send_transport); AudioSendStream::Config degrade_config = config; @@ -189,7 +201,7 @@ VideoSendStream* DegradedCall::CreateVideoSendStream( VideoSendStream::Config config, VideoEncoderConfig encoder_config) { std::unique_ptr transport_adapter; - if (send_config_) { + if (!send_configs_.empty()) { transport_adapter = std::make_unique( send_pipe_.get(), call_.get(), clock_, config.send_transport); config.send_transport = transport_adapter.get(); @@ -207,7 +219,7 @@ VideoSendStream* DegradedCall::CreateVideoSendStream( VideoEncoderConfig encoder_config, std::unique_ptr fec_controller) { std::unique_ptr transport_adapter; - if (send_config_) { + if (!send_configs_.empty()) { transport_adapter = std::make_unique( send_pipe_.get(), call_.get(), clock_, config.send_transport); config.send_transport = transport_adapter.get(); @@ -251,7 +263,7 @@ void DegradedCall::AddAdaptationResource( } PacketReceiver* DegradedCall::Receiver() { - if (receive_config_) { + if (!receive_configs_.empty()) { return this; } return call_->Receiver(); @@ -299,7 +311,7 @@ void DegradedCall::OnUpdateSyncGroup(AudioReceiveStream& stream, } void DegradedCall::OnSentPacket(const rtc::SentPacket& sent_packet) { - if (send_config_) { + if (!send_configs_.empty()) { // If we have a degraded send-transport, we have already notified call // about the supposed network send time. Discard the actual network send // time in order to properly fool the BWE. @@ -325,4 +337,21 @@ PacketReceiver::DeliveryStatus DegradedCall::DeliverPacket( receive_pipe_->Process(); return status; } + +void DegradedCall::UpdateSendNetworkConfig() { + send_config_index_ = (send_config_index_ + 1) % send_configs_.size(); + send_simulated_network_->SetConfig(send_configs_[send_config_index_]); + call_->network_thread()->PostDelayedTask( + ToQueuedTask(task_safety_, [this] { UpdateSendNetworkConfig(); }), + send_configs_[send_config_index_].duration.ms()); +} + +void DegradedCall::UpdateReceiveNetworkConfig() { + receive_config_index_ = (receive_config_index_ + 1) % receive_configs_.size(); + receive_simulated_network_->SetConfig( + receive_configs_[receive_config_index_]); + call_->network_thread()->PostDelayedTask( + ToQueuedTask(task_safety_, [this] { UpdateReceiveNetworkConfig(); }), + receive_configs_[receive_config_index_].duration.ms()); +} } // namespace webrtc diff --git a/call/degraded_call.h b/call/degraded_call.h index e11870ade8..87a83f9730 100644 --- a/call/degraded_call.h +++ b/call/degraded_call.h @@ -17,6 +17,7 @@ #include #include #include +#include #include "absl/types/optional.h" #include "api/call/transport.h" @@ -38,15 +39,20 @@ #include "rtc_base/copy_on_write_buffer.h" #include "rtc_base/network/sent_packet.h" #include "rtc_base/task_queue.h" +#include "rtc_base/task_utils/pending_task_safety_flag.h" #include "system_wrappers/include/clock.h" namespace webrtc { class DegradedCall : public Call, private PacketReceiver { public: + struct TimeScopedNetworkConfig : public BuiltInNetworkBehaviorConfig { + TimeDelta duration = TimeDelta::PlusInfinity(); + }; + explicit DegradedCall( std::unique_ptr call, - absl::optional send_config, - absl::optional receive_config, + const std::vector& send_configs, + const std::vector& receive_configs, TaskQueueFactory* task_queue_factory); ~DegradedCall() override; @@ -157,14 +163,17 @@ class DegradedCall : public Call, private PacketReceiver { Transport* const real_transport_; }; - Clock* const clock_; - const std::unique_ptr call_; - TaskQueueFactory* const task_queue_factory_; - void SetClientBitratePreferences( const webrtc::BitrateSettings& preferences) override {} + void UpdateSendNetworkConfig(); + void UpdateReceiveNetworkConfig(); - const absl::optional send_config_; + Clock* const clock_; + const std::unique_ptr call_; + ScopedTaskSafety task_safety_; + TaskQueueFactory* const task_queue_factory_; + size_t send_config_index_; + const std::vector send_configs_; SimulatedNetwork* send_simulated_network_; std::unique_ptr send_pipe_; std::map> @@ -172,7 +181,8 @@ class DegradedCall : public Call, private PacketReceiver { std::map> video_send_transport_adapters_; - const absl::optional receive_config_; + size_t receive_config_index_; + const std::vector receive_configs_; SimulatedNetwork* receive_simulated_network_; std::unique_ptr receive_pipe_; };