diff --git a/call/rtp_video_sender.cc b/call/rtp_video_sender.cc index 56c23d905f..66148061f3 100644 --- a/call/rtp_video_sender.cc +++ b/call/rtp_video_sender.cc @@ -197,7 +197,6 @@ std::vector CreateRtpStreamSenders( FrameEncryptorInterface* frame_encryptor, const CryptoOptions& crypto_options, rtc::scoped_refptr frame_transformer, - bool use_deferred_fec, const WebRtcKeyValueConfig& trials) { RTC_DCHECK_GT(rtp_config.ssrcs.size(), 0); @@ -245,9 +244,6 @@ std::vector CreateRtpStreamSenders( std::unique_ptr fec_generator = MaybeCreateFecGenerator(clock, rtp_config, suspended_ssrcs, i, trials); configuration.fec_generator = fec_generator.get(); - if (!use_deferred_fec) { - video_config.fec_generator = fec_generator.get(); - } configuration.rtx_send_ssrc = rtp_config.GetRtxSsrcAssociatedWithMediaSsrc(rtp_config.ssrcs[i]); @@ -335,9 +331,6 @@ RtpVideoSender::RtpVideoSender( field_trials_.Lookup("WebRTC-SendSideBwe-WithOverhead"), "Enabled")), has_packet_feedback_(TransportSeqNumExtensionConfigured(rtp_config)), - use_deferred_fec_(!absl::StartsWith( - field_trials_.Lookup("WebRTC-DeferredFecGeneration"), - "Disabled")), active_(false), module_process_thread_(nullptr), suspended_ssrcs_(std::move(suspended_ssrcs)), @@ -356,7 +349,6 @@ RtpVideoSender::RtpVideoSender( frame_encryptor, crypto_options, std::move(frame_transformer), - use_deferred_fec_, field_trials_)), rtp_config_(rtp_config), codec_type_(GetVideoCodecType(rtp_config)), @@ -844,7 +836,6 @@ int RtpVideoSender::ProtectionRequest(const FecProtectionParams* delta_params, *sent_nack_rate_bps = 0; *sent_fec_rate_bps = 0; for (const RtpStreamSender& stream : rtp_streams_) { - if (use_deferred_fec_) { stream.rtp_rtcp->SetFecProtectionParams(*delta_params, *key_params); auto send_bitrate = stream.rtp_rtcp->GetSendRates(); @@ -853,17 +844,6 @@ int RtpVideoSender::ProtectionRequest(const FecProtectionParams* delta_params, send_bitrate[RtpPacketMediaType::kForwardErrorCorrection].bps(); *sent_nack_rate_bps += send_bitrate[RtpPacketMediaType::kRetransmission].bps(); - } else { - if (stream.fec_generator) { - stream.fec_generator->SetProtectionParameters(*delta_params, - *key_params); - *sent_fec_rate_bps += stream.fec_generator->CurrentFecRate().bps(); - } - *sent_video_rate_bps += stream.sender_video->VideoBitrateSent(); - *sent_nack_rate_bps += - stream.rtp_rtcp->GetSendRates()[RtpPacketMediaType::kRetransmission] - .bps(); - } } return 0; } diff --git a/call/rtp_video_sender.h b/call/rtp_video_sender.h index 5eaaa29f2d..2e2d1981de 100644 --- a/call/rtp_video_sender.h +++ b/call/rtp_video_sender.h @@ -172,7 +172,6 @@ class RtpVideoSender : public RtpVideoSenderInterface, const FieldTrialBasedConfig field_trials_; const bool send_side_bwe_with_overhead_; const bool has_packet_feedback_; - const bool use_deferred_fec_; // TODO(holmer): Remove mutex_ once RtpVideoSender runs on the // transport task queue. diff --git a/modules/pacing/pacing_controller_unittest.cc b/modules/pacing/pacing_controller_unittest.cc index 8aaa67ce51..7340282c07 100644 --- a/modules/pacing/pacing_controller_unittest.cc +++ b/modules/pacing/pacing_controller_unittest.cc @@ -2106,10 +2106,7 @@ TEST_P(PacingControllerTest, PaddingTargetAccountsForPaddingRate) { AdvanceTimeAndProcess(); } -TEST_P(PacingControllerTest, SendsDeferredFecPackets) { - ScopedFieldTrials trial("WebRTC-DeferredFecGeneration/Enabled/"); - SetUp(); - +TEST_P(PacingControllerTest, SendsFecPackets) { const uint32_t kSsrc = 12345; const uint32_t kFlexSsrc = 54321; uint16_t sequence_number = 1234; diff --git a/modules/rtp_rtcp/source/rtp_sender_egress.cc b/modules/rtp_rtcp/source/rtp_sender_egress.cc index dbd96e461e..4252851c50 100644 --- a/modules/rtp_rtcp/source/rtp_sender_egress.cc +++ b/modules/rtp_rtcp/source/rtp_sender_egress.cc @@ -101,11 +101,7 @@ RtpSenderEgress::RtpSenderEgress(const RtpRtcpInterface::Configuration& config, is_audio_(config.audio), #endif need_rtp_packet_infos_(config.need_rtp_packet_infos), - fec_generator_(!IsTrialSetTo(config.field_trials, - "WebRTC-DeferredFecGeneration", - "Disabled") - ? config.fec_generator - : nullptr), + fec_generator_(config.fec_generator), transport_feedback_observer_(config.transport_feedback_callback), send_side_delay_observer_(config.send_side_delay_observer), send_packet_observer_(config.send_packet_observer), @@ -176,7 +172,7 @@ void RtpSenderEgress::SendPacket(RtpPacketToSend* packet, } if (fec_generator_ && packet->fec_protect_packet()) { - // Deferred fec generation is used, add packet to generator. + // This packet should be protected by FEC, add it to packet generator. RTC_DCHECK(fec_generator_); RTC_DCHECK(packet->packet_type() == RtpPacketMediaType::kVideo); absl::optional> diff --git a/modules/rtp_rtcp/source/rtp_sender_unittest.cc b/modules/rtp_rtcp/source/rtp_sender_unittest.cc index 0fb30cf0fe..38f2d10001 100644 --- a/modules/rtp_rtcp/source/rtp_sender_unittest.cc +++ b/modules/rtp_rtcp/source/rtp_sender_unittest.cc @@ -143,10 +143,8 @@ MATCHER_P(SameRtcEventTypeAs, value, "") { } struct TestConfig { - TestConfig(bool with_overhead, bool deferred_fec) - : with_overhead(with_overhead), deferred_fec(deferred_fec) {} + explicit TestConfig(bool with_overhead) : with_overhead(with_overhead) {} bool with_overhead = false; - bool deferred_fec = false; }; class MockRtpPacketPacer : public RtpPacketSender { @@ -283,12 +281,10 @@ class FieldTrialConfig : public WebRtcKeyValueConfig { public: FieldTrialConfig() : overhead_enabled_(false), - deferred_fec_(false), max_padding_factor_(1200) {} ~FieldTrialConfig() override {} void SetOverHeadEnabled(bool enabled) { overhead_enabled_ = enabled; } - void UseDeferredFec(bool enabled) { deferred_fec_ = enabled; } void SetMaxPaddingFactor(double factor) { max_padding_factor_ = factor; } std::string Lookup(absl::string_view key) const override { @@ -299,15 +295,12 @@ class FieldTrialConfig : public WebRtcKeyValueConfig { return ssb.str(); } else if (key == "WebRTC-SendSideBwe-WithOverhead") { return overhead_enabled_ ? "Enabled" : "Disabled"; - } else if (key == "WebRTC-DeferredFecGeneration") { - return deferred_fec_ ? "Enabled" : "Disabled"; } return ""; } private: bool overhead_enabled_; - bool deferred_fec_; double max_padding_factor_; }; @@ -329,7 +322,6 @@ class RtpSenderTest : public ::testing::TestWithParam { clock_), kMarkerBit(true) { field_trials_.SetOverHeadEnabled(GetParam().with_overhead); - field_trials_.UseDeferredFec(GetParam().deferred_fec); } void SetUp() override { SetUpRtpSender(true, false, false); } @@ -1339,9 +1331,6 @@ TEST_P(RtpSenderTest, SendFlexfecPackets) { RTPSenderVideo::Config video_config; video_config.clock = clock_; video_config.rtp_sender = rtp_sender(); - if (!GetParam().deferred_fec) { - video_config.fec_generator = &flexfec_sender; - } video_config.fec_type = flexfec_sender.GetFecType(); video_config.fec_overhead_bytes = flexfec_sender.MaxPacketOverhead(); video_config.fec_type = flexfec_sender.GetFecType(); @@ -1369,7 +1358,7 @@ TEST_P(RtpSenderTest, SendFlexfecPackets) { EXPECT_EQ(packet->Ssrc(), kSsrc); EXPECT_EQ(packet->SequenceNumber(), kSeqNum); media_packet = std::move(packet); - if (GetParam().deferred_fec) { + // Simulate RtpSenderEgress adding packet to fec generator. flexfec_sender.AddPacketAndGenerateFec(*media_packet); auto fec_packets = flexfec_sender.GetFecPackets(); @@ -1378,7 +1367,6 @@ TEST_P(RtpSenderTest, SendFlexfecPackets) { EXPECT_EQ(fec_packet->packet_type(), RtpPacketMediaType::kForwardErrorCorrection); EXPECT_EQ(fec_packet->Ssrc(), kFlexFecSsrc); - } } else { EXPECT_EQ(packet->packet_type(), RtpPacketMediaType::kForwardErrorCorrection); @@ -1440,9 +1428,6 @@ TEST_P(RtpSenderTestWithoutPacer, SendFlexfecPackets) { RTPSenderVideo::Config video_config; video_config.clock = clock_; video_config.rtp_sender = rtp_sender(); - if (!GetParam().deferred_fec) { - video_config.fec_generator = &flexfec_sender; - } video_config.fec_type = flexfec_sender.GetFecType(); video_config.fec_overhead_bytes = flexfec_sender_.MaxPacketOverhead(); video_config.field_trials = &field_trials; @@ -1453,11 +1438,7 @@ TEST_P(RtpSenderTestWithoutPacer, SendFlexfecPackets) { params.fec_rate = 15; params.max_fec_frames = 1; params.fec_mask_type = kFecMaskRandom; - if (GetParam().deferred_fec) { - rtp_egress()->SetFecProtectionParameters(params, params); - } else { - flexfec_sender.SetProtectionParameters(params, params); - } + rtp_egress()->SetFecProtectionParameters(params, params); EXPECT_CALL(mock_rtc_event_log_, LogProxy(SameRtcEventTypeAs(RtcEvent::Type::RtpPacketOutgoing))) @@ -1768,9 +1749,6 @@ TEST_P(RtpSenderTest, FecOverheadRate) { RTPSenderVideo::Config video_config; video_config.clock = clock_; video_config.rtp_sender = rtp_sender(); - if (!GetParam().deferred_fec) { - video_config.fec_generator = &flexfec_sender; - } video_config.fec_type = flexfec_sender.GetFecType(); video_config.fec_overhead_bytes = flexfec_sender.MaxPacketOverhead(); video_config.field_trials = &field_trials; @@ -1780,11 +1758,7 @@ TEST_P(RtpSenderTest, FecOverheadRate) { params.fec_rate = 15; params.max_fec_frames = 1; params.fec_mask_type = kFecMaskRandom; - if (GetParam().deferred_fec) { - rtp_egress()->SetFecProtectionParameters(params, params); - } else { - flexfec_sender.SetProtectionParameters(params, params); - } + rtp_egress()->SetFecProtectionParameters(params, params); constexpr size_t kNumMediaPackets = 10; constexpr size_t kNumFecPackets = kNumMediaPackets; @@ -1806,7 +1780,6 @@ TEST_P(RtpSenderTest, FecOverheadRate) { constexpr size_t kPacketLength = kRtpHeaderLength + kFlexfecHeaderLength + kGenericCodecHeaderLength + kPayloadLength; - if (GetParam().deferred_fec) { EXPECT_NEAR( kNumFecPackets * kPacketLength * 8 / (kNumFecPackets * kTimeBetweenPacketsMs / 1000.0f), @@ -1814,11 +1787,6 @@ TEST_P(RtpSenderTest, FecOverheadRate) { ->GetSendRates()[RtpPacketMediaType::kForwardErrorCorrection] .bps(), 500); - } else { - EXPECT_NEAR(kNumFecPackets * kPacketLength * 8 / - (kNumFecPackets * kTimeBetweenPacketsMs / 1000.0f), - flexfec_sender.CurrentFecRate().bps(), 500); - } } TEST_P(RtpSenderTest, BitrateCallbacks) { @@ -1970,9 +1938,6 @@ TEST_P(RtpSenderTestWithoutPacer, StreamDataCountersCallbacksUlpfec) { video_config.rtp_sender = rtp_sender(); video_config.field_trials = &field_trials_; video_config.red_payload_type = kRedPayloadType; - if (!GetParam().deferred_fec) { - video_config.fec_generator = &ulpfec_generator; - } video_config.fec_type = ulpfec_generator.GetFecType(); video_config.fec_overhead_bytes = ulpfec_generator.MaxPacketOverhead(); RTPSenderVideo rtp_sender_video(video_config); @@ -1989,11 +1954,7 @@ TEST_P(RtpSenderTestWithoutPacer, StreamDataCountersCallbacksUlpfec) { fec_params.fec_mask_type = kFecMaskRandom; fec_params.fec_rate = 1; fec_params.max_fec_frames = 1; - if (GetParam().deferred_fec) { - rtp_egress()->SetFecProtectionParameters(fec_params, fec_params); - } else { - ulpfec_generator.SetProtectionParameters(fec_params, fec_params); - } + rtp_egress()->SetFecProtectionParameters(fec_params, fec_params); video_header.frame_type = VideoFrameType::kVideoFrameDelta; ASSERT_TRUE(rtp_sender_video.SendVideo(kPayloadType, kCodecType, 1234, 4321, payload, video_header, @@ -2823,11 +2784,6 @@ TEST_P(RtpSenderTest, IgnoresNackAfterDisablingMedia) { } TEST_P(RtpSenderTest, DoesntFecProtectRetransmissions) { - if (!GetParam().deferred_fec) { - // This test make sense only for deferred fec generation. - return; - } - // Set up retranmission without RTX, so that a plain copy of the old packet is // re-sent instead. const int64_t kRtt = 10; @@ -2864,16 +2820,12 @@ TEST_P(RtpSenderTest, DoesntFecProtectRetransmissions) { INSTANTIATE_TEST_SUITE_P(WithAndWithoutOverhead, RtpSenderTest, - ::testing::Values(TestConfig{false, false}, - TestConfig{false, true}, - TestConfig{true, false}, - TestConfig{false, false})); + ::testing::Values(TestConfig{false}, + TestConfig{true})); INSTANTIATE_TEST_SUITE_P(WithAndWithoutOverhead, RtpSenderTestWithoutPacer, - ::testing::Values(TestConfig{false, false}, - TestConfig{false, true}, - TestConfig{true, false}, - TestConfig{false, false})); + ::testing::Values(TestConfig{false}, + TestConfig{true})); } // namespace webrtc diff --git a/modules/rtp_rtcp/source/rtp_sender_video.cc b/modules/rtp_rtcp/source/rtp_sender_video.cc index 8ce1eed913..5e3669309d 100644 --- a/modules/rtp_rtcp/source/rtp_sender_video.cc +++ b/modules/rtp_rtcp/source/rtp_sender_video.cc @@ -144,10 +144,8 @@ RTPSenderVideo::RTPSenderVideo(const Config& config) playout_delay_pending_(false), forced_playout_delay_(LoadVideoPlayoutDelayOverride(config.field_trials)), red_payload_type_(config.red_payload_type), - fec_generator_(config.fec_generator), fec_type_(config.fec_type), fec_overhead_bytes_(config.fec_overhead_bytes), - video_bitrate_(1000, RateStatistics::kBpsScale), packetization_overhead_bitrate_(1000, RateStatistics::kBpsScale), frame_encryptor_(config.frame_encryptor), require_frame_encryption_(config.require_frame_encryption), @@ -179,27 +177,11 @@ RTPSenderVideo::~RTPSenderVideo() { void RTPSenderVideo::LogAndSendToNetwork( std::vector> packets, size_t unpacketized_payload_size) { - int64_t now_ms = clock_->TimeInMilliseconds(); -#if BWE_TEST_LOGGING_COMPILE_TIME_ENABLE - if (fec_generator_) { - uint32_t fec_rate_kbps = fec_generator_->CurrentFecRate().kbps(); - for (const auto& packet : packets) { - if (packet->packet_type() == - RtpPacketMediaType::kForwardErrorCorrection) { - const uint32_t ssrc = packet->Ssrc(); - BWE_TEST_LOGGING_PLOT_WITH_SSRC(1, "VideoFecBitrate_kbps", now_ms, - fec_rate_kbps, ssrc); - } - } - } -#endif - { MutexLock lock(&stats_mutex_); size_t packetized_payload_size = 0; for (const auto& packet : packets) { if (*packet->packet_type() == RtpPacketMediaType::kVideo) { - video_bitrate_.Update(packet->size(), now_ms); packetized_payload_size += packet->payload_size(); } } @@ -449,9 +431,15 @@ bool RTPSenderVideo::SendVideo( video_header.generic->frame_id, video_header.generic->chain_diffs); } + const uint8_t temporal_id = GetTemporalId(video_header); + // No FEC protection for upper temporal layers, if used. + const bool use_fec = fec_type_.has_value() && + (temporal_id == 0 || temporal_id == kNoTemporalIdx); + // Maximum size of packet including rtp headers. // Extra space left in case packet will be resent using fec or rtx. - int packet_capacity = rtp_sender_->MaxRtpPacketSize() - FecPacketOverhead() - + int packet_capacity = rtp_sender_->MaxRtpPacketSize() - + (use_fec ? FecPacketOverhead() : 0) - (rtp_sender_->RtxStatus() ? kRtxHeaderSize : 0); std::unique_ptr single_packet = @@ -511,8 +499,8 @@ bool RTPSenderVideo::SendVideo( first_packet->HasExtension() || first_packet->HasExtension(); - // Minimization of the vp8 descriptor may erase temporal_id, so save it. - const uint8_t temporal_id = GetTemporalId(video_header); + // Minimization of the vp8 descriptor may erase temporal_id, so use + // |temporal_id| rather than reference |video_header| beyond this point. if (has_generic_descriptor) { MinimizeDescriptor(&video_header); } @@ -605,18 +593,11 @@ bool RTPSenderVideo::SendVideo( packet->set_packetization_finish_time_ms(clock_->TimeInMilliseconds()); } - // No FEC protection for upper temporal layers, if used. - if (fec_type_.has_value() && - (temporal_id == 0 || temporal_id == kNoTemporalIdx)) { - if (fec_generator_) { - fec_generator_->AddPacketAndGenerateFec(*packet); - } else { - // Deferred FEC generation, just mark packet. - packet->set_fec_protect_packet(true); - } - } + packet->set_fec_protect_packet(use_fec); if (red_enabled()) { + // TODO(sprang): Consider packetizing directly into packets with the RED + // header already in place, to avoid this copy. std::unique_ptr red_packet(new RtpPacketToSend(*packet)); BuildRedPayload(*packet, red_packet.get()); red_packet->SetPayloadType(*red_payload_type_); @@ -643,19 +624,6 @@ bool RTPSenderVideo::SendVideo( } } - if (fec_generator_) { - // Fetch any FEC packets generated from the media frame and add them to - // the list of packets to send. - auto fec_packets = fec_generator_->GetFecPackets(); - const bool generate_sequence_numbers = !fec_generator_->FecSsrc(); - for (auto& fec_packet : fec_packets) { - if (generate_sequence_numbers) { - rtp_sender_->AssignSequenceNumber(fec_packet.get()); - } - rtp_packets.emplace_back(std::move(fec_packet)); - } - } - LogAndSendToNetwork(std::move(rtp_packets), payload.size()); // Update details about the last sent frame. @@ -704,11 +672,6 @@ bool RTPSenderVideo::SendEncodedImage( expected_retransmission_time_ms); } -uint32_t RTPSenderVideo::VideoBitrateSent() const { - MutexLock lock(&stats_mutex_); - return video_bitrate_.Rate(clock_->TimeInMilliseconds()).value_or(0); -} - uint32_t RTPSenderVideo::PacketizationOverheadBps() const { MutexLock lock(&stats_mutex_); return packetization_overhead_bitrate_.Rate(clock_->TimeInMilliseconds()) diff --git a/modules/rtp_rtcp/source/rtp_sender_video.h b/modules/rtp_rtcp/source/rtp_sender_video.h index 8cc4d68cb0..7e70ef245a 100644 --- a/modules/rtp_rtcp/source/rtp_sender_video.h +++ b/modules/rtp_rtcp/source/rtp_sender_video.h @@ -70,8 +70,6 @@ class RTPSenderVideo { // expected to outlive the RTPSenderVideo object they are passed to. Clock* clock = nullptr; RTPSender* rtp_sender = nullptr; - FlexfecSender* flexfec_sender = nullptr; - VideoFecGenerator* fec_generator = nullptr; // Some FEC data is duplicated here in preparation of moving FEC to // the egress stage. absl::optional fec_type; @@ -122,11 +120,11 @@ class RTPSenderVideo { void SetVideoStructureUnderLock( const FrameDependencyStructure* video_structure); - uint32_t VideoBitrateSent() const; - // Returns the current packetization overhead rate, in bps. Note that this is // the payload overhead, eg the VP8 payload headers, not the RTP headers // or extension/ + // TODO(sprang): Consider moving this to RtpSenderEgress so it's in the same + // place as the other rate stats. uint32_t PacketizationOverheadBps() const; protected: @@ -197,13 +195,10 @@ class RTPSenderVideo { Mutex mutex_; const absl::optional red_payload_type_; - VideoFecGenerator* const fec_generator_; absl::optional fec_type_; const size_t fec_overhead_bytes_; // Per packet max FEC overhead. mutable Mutex stats_mutex_; - // Bitrate used for video payload and RTP headers. - RateStatistics video_bitrate_ RTC_GUARDED_BY(stats_mutex_); RateStatistics packetization_overhead_bitrate_ RTC_GUARDED_BY(stats_mutex_); std::map frame_stats_by_temporal_layer_ diff --git a/modules/rtp_rtcp/source/rtp_sender_video_unittest.cc b/modules/rtp_rtcp/source/rtp_sender_video_unittest.cc index b9e7fcbe0c..9d4f81fc79 100644 --- a/modules/rtp_rtcp/source/rtp_sender_video_unittest.cc +++ b/modules/rtp_rtcp/source/rtp_sender_video_unittest.cc @@ -123,13 +123,11 @@ class TestRtpSenderVideo : public RTPSenderVideo { public: TestRtpSenderVideo(Clock* clock, RTPSender* rtp_sender, - FlexfecSender* flexfec_sender, const WebRtcKeyValueConfig& field_trials) : RTPSenderVideo([&] { Config config; config.clock = clock; config.rtp_sender = rtp_sender; - config.fec_generator = flexfec_sender; config.field_trials = &field_trials; return config; }()) {} @@ -186,7 +184,6 @@ class RtpSenderVideoTest : public ::testing::TestWithParam { rtp_sender_video_( std::make_unique(&fake_clock_, rtp_module_->RtpSender(), - nullptr, field_trials_)) { rtp_module_->SetSequenceNumber(kSeqNum); rtp_module_->SetStartTimestamp(0); @@ -859,7 +856,7 @@ TEST_P(RtpSenderVideoTest, AbsoluteCaptureTime) { TEST_P(RtpSenderVideoTest, AbsoluteCaptureTimeWithCaptureClockOffset) { field_trials_.set_include_capture_clock_offset(true); rtp_sender_video_ = std::make_unique( - &fake_clock_, rtp_module_->RtpSender(), nullptr, field_trials_); + &fake_clock_, rtp_module_->RtpSender(), field_trials_); constexpr int64_t kAbsoluteCaptureTimestampMs = 12345678; uint8_t kFrame[kMaxPacketLength]; diff --git a/test/scenario/video_stream_unittest.cc b/test/scenario/video_stream_unittest.cc index 873ef639ba..19735a8fab 100644 --- a/test/scenario/video_stream_unittest.cc +++ b/test/scenario/video_stream_unittest.cc @@ -171,25 +171,6 @@ TEST(VideoStreamTest, SendsFecWithFlexFec) { EXPECT_GT(video_stats.substreams.begin()->second.rtp_stats.fec.packets, 0u); } -TEST(VideoStreamTest, SendsFecWithDeferredFlexFec) { - ScopedFieldTrials trial("WebRTC-DeferredFecGeneration/Enabled/"); - Scenario s; - auto route = - s.CreateRoutes(s.CreateClient("caller", CallClientConfig()), - {s.CreateSimulationNode([](NetworkSimulationConfig* c) { - c->loss_rate = 0.1; - c->delay = TimeDelta::Millis(100); - })}, - s.CreateClient("callee", CallClientConfig()), - {s.CreateSimulationNode(NetworkSimulationConfig())}); - auto video = s.CreateVideoStream(route->forward(), [&](VideoStreamConfig* c) { - c->stream.use_flexfec = true; - }); - s.RunFor(TimeDelta::Seconds(5)); - VideoSendStream::Stats video_stats = video->send()->GetStats(); - EXPECT_GT(video_stats.substreams.begin()->second.rtp_stats.fec.packets, 0u); -} - TEST(VideoStreamTest, ResolutionAdaptsToAvailableBandwidth) { // Declared before scenario to avoid use after free. std::atomic num_qvga_frames_(0);