| /* | 
 |  *  Copyright (c) 2013 The WebRTC project authors. All Rights Reserved. | 
 |  * | 
 |  *  Use of this source code is governed by a BSD-style license | 
 |  *  that can be found in the LICENSE file in the root of the source | 
 |  *  tree. An additional intellectual property rights grant can be found | 
 |  *  in the file PATENTS.  All contributing project authors may | 
 |  *  be found in the AUTHORS file in the root of the source tree. | 
 |  */ | 
 | #include <algorithm>  // max | 
 | #include <memory> | 
 | #include <vector> | 
 |  | 
 | #include "absl/algorithm/container.h" | 
 | #include "api/sequence_checker.h" | 
 | #include "api/task_queue/default_task_queue_factory.h" | 
 | #include "api/task_queue/task_queue_base.h" | 
 | #include "api/test/simulated_network.h" | 
 | #include "api/video/builtin_video_bitrate_allocator_factory.h" | 
 | #include "api/video/encoded_image.h" | 
 | #include "api/video/video_bitrate_allocation.h" | 
 | #include "api/video_codecs/video_encoder.h" | 
 | #include "call/call.h" | 
 | #include "call/fake_network_pipe.h" | 
 | #include "call/rtp_transport_controller_send.h" | 
 | #include "call/simulated_network.h" | 
 | #include "call/video_send_stream.h" | 
 | #include "media/engine/internal_encoder_factory.h" | 
 | #include "media/engine/simulcast_encoder_adapter.h" | 
 | #include "media/engine/webrtc_video_engine.h" | 
 | #include "modules/rtp_rtcp/include/rtp_header_extension_map.h" | 
 | #include "modules/rtp_rtcp/source/create_video_rtp_depacketizer.h" | 
 | #include "modules/rtp_rtcp/source/rtcp_sender.h" | 
 | #include "modules/rtp_rtcp/source/rtp_header_extensions.h" | 
 | #include "modules/rtp_rtcp/source/rtp_packet.h" | 
 | #include "modules/rtp_rtcp/source/rtp_rtcp_impl2.h" | 
 | #include "modules/rtp_rtcp/source/rtp_util.h" | 
 | #include "modules/rtp_rtcp/source/video_rtp_depacketizer_vp9.h" | 
 | #include "modules/video_coding/codecs/interface/common_constants.h" | 
 | #include "modules/video_coding/codecs/vp8/include/vp8.h" | 
 | #include "modules/video_coding/codecs/vp9/include/vp9.h" | 
 | #include "modules/video_coding/svc/scalability_mode_util.h" | 
 | #include "rtc_base/checks.h" | 
 | #include "rtc_base/event.h" | 
 | #include "rtc_base/experiments/alr_experiment.h" | 
 | #include "rtc_base/logging.h" | 
 | #include "rtc_base/platform_thread.h" | 
 | #include "rtc_base/rate_limiter.h" | 
 | #include "rtc_base/strings/string_builder.h" | 
 | #include "rtc_base/synchronization/mutex.h" | 
 | #include "rtc_base/task_queue_for_test.h" | 
 | #include "rtc_base/task_utils/to_queued_task.h" | 
 | #include "rtc_base/time_utils.h" | 
 | #include "rtc_base/unique_id_generator.h" | 
 | #include "system_wrappers/include/sleep.h" | 
 | #include "test/call_test.h" | 
 | #include "test/configurable_frame_size_encoder.h" | 
 | #include "test/fake_encoder.h" | 
 | #include "test/fake_texture_frame.h" | 
 | #include "test/frame_forwarder.h" | 
 | #include "test/frame_generator_capturer.h" | 
 | #include "test/frame_utils.h" | 
 | #include "test/gmock.h" | 
 | #include "test/gtest.h" | 
 | #include "test/null_transport.h" | 
 | #include "test/rtcp_packet_parser.h" | 
 | #include "test/testsupport/perf_test.h" | 
 | #include "test/video_encoder_proxy_factory.h" | 
 | #include "video/send_statistics_proxy.h" | 
 | #include "video/transport_adapter.h" | 
 | #include "video/video_send_stream.h" | 
 |  | 
 | namespace webrtc { | 
 | namespace test { | 
 | class VideoSendStreamPeer { | 
 |  public: | 
 |   explicit VideoSendStreamPeer(webrtc::VideoSendStream* base_class_stream) | 
 |       : internal_stream_( | 
 |             static_cast<internal::VideoSendStream*>(base_class_stream)) {} | 
 |   absl::optional<float> GetPacingFactorOverride() const { | 
 |     return internal_stream_->GetPacingFactorOverride(); | 
 |   } | 
 |  | 
 |  private: | 
 |   internal::VideoSendStream const* const internal_stream_; | 
 | }; | 
 | }  // namespace test | 
 |  | 
 | namespace { | 
 | enum : int {  // The first valid value is 1. | 
 |   kAbsSendTimeExtensionId = 1, | 
 |   kTimestampOffsetExtensionId, | 
 |   kTransportSequenceNumberExtensionId, | 
 |   kVideoContentTypeExtensionId, | 
 |   kVideoRotationExtensionId, | 
 |   kVideoTimingExtensionId, | 
 | }; | 
 |  | 
 | // Readability convenience enum for `WaitBitrateChanged()`. | 
 | enum class WaitUntil : bool { kZero = false, kNonZero = true }; | 
 |  | 
 | constexpr int64_t kRtcpIntervalMs = 1000; | 
 |  | 
 | enum VideoFormat { | 
 |   kGeneric, | 
 |   kVP8, | 
 | }; | 
 |  | 
 | struct Vp9TestParams { | 
 |   std::string scalability_mode; | 
 |   uint8_t num_spatial_layers; | 
 |   uint8_t num_temporal_layers; | 
 |   InterLayerPredMode inter_layer_pred; | 
 | }; | 
 | }  // namespace | 
 |  | 
 | class VideoSendStreamTest : public test::CallTest { | 
 |  public: | 
 |   VideoSendStreamTest() { | 
 |     RegisterRtpExtension(RtpExtension(RtpExtension::kTransportSequenceNumberUri, | 
 |                                       kTransportSequenceNumberExtensionId)); | 
 |   } | 
 |  | 
 |  protected: | 
 |   void TestNackRetransmission(uint32_t retransmit_ssrc, | 
 |                               uint8_t retransmit_payload_type); | 
 |   void TestPacketFragmentationSize(VideoFormat format, bool with_fec); | 
 |  | 
 |   void TestVp9NonFlexMode(const Vp9TestParams& params, | 
 |                           bool use_scalability_mode_identifier); | 
 |  | 
 |   void TestRequestSourceRotateVideo(bool support_orientation_ext); | 
 |  | 
 |   void TestTemporalLayers(VideoEncoderFactory* encoder_factory, | 
 |                           const std::string& payload_name, | 
 |                           const std::vector<int>& num_temporal_layers, | 
 |                           const std::vector<ScalabilityMode>& scalability_mode); | 
 | }; | 
 |  | 
 | TEST_F(VideoSendStreamTest, CanStartStartedStream) { | 
 |   SendTask(RTC_FROM_HERE, task_queue(), [this]() { | 
 |     CreateSenderCall(); | 
 |  | 
 |     test::NullTransport transport; | 
 |     CreateSendConfig(1, 0, 0, &transport); | 
 |     CreateVideoStreams(); | 
 |     GetVideoSendStream()->Start(); | 
 |     GetVideoSendStream()->Start(); | 
 |     DestroyStreams(); | 
 |     DestroyCalls(); | 
 |   }); | 
 | } | 
 |  | 
 | TEST_F(VideoSendStreamTest, CanStopStoppedStream) { | 
 |   SendTask(RTC_FROM_HERE, task_queue(), [this]() { | 
 |     CreateSenderCall(); | 
 |  | 
 |     test::NullTransport transport; | 
 |     CreateSendConfig(1, 0, 0, &transport); | 
 |     CreateVideoStreams(); | 
 |     GetVideoSendStream()->Stop(); | 
 |     GetVideoSendStream()->Stop(); | 
 |     DestroyStreams(); | 
 |     DestroyCalls(); | 
 |   }); | 
 | } | 
 |  | 
 | TEST_F(VideoSendStreamTest, SupportsCName) { | 
 |   static std::string kCName = "PjQatC14dGfbVwGPUOA9IH7RlsFDbWl4AhXEiDsBizo="; | 
 |   class CNameObserver : public test::SendTest { | 
 |    public: | 
 |     CNameObserver() : SendTest(kDefaultTimeoutMs) {} | 
 |  | 
 |    private: | 
 |     Action OnSendRtcp(const uint8_t* packet, size_t length) override { | 
 |       test::RtcpPacketParser parser; | 
 |       EXPECT_TRUE(parser.Parse(packet, length)); | 
 |       if (parser.sdes()->num_packets() > 0) { | 
 |         EXPECT_EQ(1u, parser.sdes()->chunks().size()); | 
 |         EXPECT_EQ(kCName, parser.sdes()->chunks()[0].cname); | 
 |  | 
 |         observation_complete_.Set(); | 
 |       } | 
 |  | 
 |       return SEND_PACKET; | 
 |     } | 
 |  | 
 |     void ModifyVideoConfigs( | 
 |         VideoSendStream::Config* send_config, | 
 |         std::vector<VideoReceiveStream::Config>* receive_configs, | 
 |         VideoEncoderConfig* encoder_config) override { | 
 |       send_config->rtp.c_name = kCName; | 
 |     } | 
 |  | 
 |     void PerformTest() override { | 
 |       EXPECT_TRUE(Wait()) << "Timed out while waiting for RTCP with CNAME."; | 
 |     } | 
 |   } test; | 
 |  | 
 |   RunBaseTest(&test); | 
 | } | 
 |  | 
 | TEST_F(VideoSendStreamTest, SupportsAbsoluteSendTime) { | 
 |   class AbsoluteSendTimeObserver : public test::SendTest { | 
 |    public: | 
 |     AbsoluteSendTimeObserver() : SendTest(kDefaultTimeoutMs) { | 
 |       extensions_.Register<AbsoluteSendTime>(kAbsSendTimeExtensionId); | 
 |     } | 
 |  | 
 |     Action OnSendRtp(const uint8_t* packet, size_t length) override { | 
 |       RtpPacket rtp_packet(&extensions_); | 
 |       EXPECT_TRUE(rtp_packet.Parse(packet, length)); | 
 |  | 
 |       uint32_t abs_send_time = 0; | 
 |       EXPECT_FALSE(rtp_packet.HasExtension<TransmissionOffset>()); | 
 |       EXPECT_TRUE(rtp_packet.GetExtension<AbsoluteSendTime>(&abs_send_time)); | 
 |       if (abs_send_time != 0) { | 
 |         // Wait for at least one packet with a non-zero send time. The send time | 
 |         // is a 16-bit value derived from the system clock, and it is valid | 
 |         // for a packet to have a zero send time. To tell that from an | 
 |         // unpopulated value we'll wait for a packet with non-zero send time. | 
 |         observation_complete_.Set(); | 
 |       } else { | 
 |         RTC_LOG(LS_WARNING) | 
 |             << "Got a packet with zero absoluteSendTime, waiting" | 
 |                " for another packet..."; | 
 |       } | 
 |  | 
 |       return SEND_PACKET; | 
 |     } | 
 |  | 
 |     void ModifyVideoConfigs( | 
 |         VideoSendStream::Config* send_config, | 
 |         std::vector<VideoReceiveStream::Config>* receive_configs, | 
 |         VideoEncoderConfig* encoder_config) override { | 
 |       send_config->rtp.extensions.clear(); | 
 |       send_config->rtp.extensions.push_back( | 
 |           RtpExtension(RtpExtension::kAbsSendTimeUri, kAbsSendTimeExtensionId)); | 
 |     } | 
 |  | 
 |     void PerformTest() override { | 
 |       EXPECT_TRUE(Wait()) << "Timed out while waiting for single RTP packet."; | 
 |     } | 
 |  | 
 |    private: | 
 |     RtpHeaderExtensionMap extensions_; | 
 |   } test; | 
 |  | 
 |   RunBaseTest(&test); | 
 | } | 
 |  | 
 | TEST_F(VideoSendStreamTest, SupportsTransmissionTimeOffset) { | 
 |   static const int kEncodeDelayMs = 5; | 
 |   class TransmissionTimeOffsetObserver : public test::SendTest { | 
 |    public: | 
 |     TransmissionTimeOffsetObserver() | 
 |         : SendTest(kDefaultTimeoutMs), encoder_factory_([]() { | 
 |             return std::make_unique<test::DelayedEncoder>( | 
 |                 Clock::GetRealTimeClock(), kEncodeDelayMs); | 
 |           }) { | 
 |       extensions_.Register<TransmissionOffset>(kTimestampOffsetExtensionId); | 
 |     } | 
 |  | 
 |    private: | 
 |     Action OnSendRtp(const uint8_t* packet, size_t length) override { | 
 |       RtpPacket rtp_packet(&extensions_); | 
 |       EXPECT_TRUE(rtp_packet.Parse(packet, length)); | 
 |  | 
 |       int32_t toffset = 0; | 
 |       EXPECT_TRUE(rtp_packet.GetExtension<TransmissionOffset>(&toffset)); | 
 |       EXPECT_FALSE(rtp_packet.HasExtension<AbsoluteSendTime>()); | 
 |       EXPECT_GT(toffset, 0); | 
 |       observation_complete_.Set(); | 
 |  | 
 |       return SEND_PACKET; | 
 |     } | 
 |  | 
 |     void ModifyVideoConfigs( | 
 |         VideoSendStream::Config* send_config, | 
 |         std::vector<VideoReceiveStream::Config>* receive_configs, | 
 |         VideoEncoderConfig* encoder_config) override { | 
 |       send_config->encoder_settings.encoder_factory = &encoder_factory_; | 
 |       send_config->rtp.extensions.clear(); | 
 |       send_config->rtp.extensions.push_back(RtpExtension( | 
 |           RtpExtension::kTimestampOffsetUri, kTimestampOffsetExtensionId)); | 
 |     } | 
 |  | 
 |     void PerformTest() override { | 
 |       EXPECT_TRUE(Wait()) << "Timed out while waiting for a single RTP packet."; | 
 |     } | 
 |  | 
 |     test::FunctionVideoEncoderFactory encoder_factory_; | 
 |     RtpHeaderExtensionMap extensions_; | 
 |   } test; | 
 |  | 
 |   RunBaseTest(&test); | 
 | } | 
 |  | 
 | TEST_F(VideoSendStreamTest, SupportsTransportWideSequenceNumbers) { | 
 |   static const uint8_t kExtensionId = kTransportSequenceNumberExtensionId; | 
 |   class TransportWideSequenceNumberObserver : public test::SendTest { | 
 |    public: | 
 |     TransportWideSequenceNumberObserver() | 
 |         : SendTest(kDefaultTimeoutMs), encoder_factory_([]() { | 
 |             return std::make_unique<test::FakeEncoder>( | 
 |                 Clock::GetRealTimeClock()); | 
 |           }) { | 
 |       extensions_.Register<TransportSequenceNumber>(kExtensionId); | 
 |     } | 
 |  | 
 |    private: | 
 |     Action OnSendRtp(const uint8_t* packet, size_t length) override { | 
 |       RtpPacket rtp_packet(&extensions_); | 
 |       EXPECT_TRUE(rtp_packet.Parse(packet, length)); | 
 |  | 
 |       EXPECT_TRUE(rtp_packet.HasExtension<TransportSequenceNumber>()); | 
 |       EXPECT_FALSE(rtp_packet.HasExtension<TransmissionOffset>()); | 
 |       EXPECT_FALSE(rtp_packet.HasExtension<AbsoluteSendTime>()); | 
 |  | 
 |       observation_complete_.Set(); | 
 |  | 
 |       return SEND_PACKET; | 
 |     } | 
 |  | 
 |     void ModifyVideoConfigs( | 
 |         VideoSendStream::Config* send_config, | 
 |         std::vector<VideoReceiveStream::Config>* receive_configs, | 
 |         VideoEncoderConfig* encoder_config) override { | 
 |       send_config->encoder_settings.encoder_factory = &encoder_factory_; | 
 |     } | 
 |  | 
 |     void PerformTest() override { | 
 |       EXPECT_TRUE(Wait()) << "Timed out while waiting for a single RTP packet."; | 
 |     } | 
 |  | 
 |     test::FunctionVideoEncoderFactory encoder_factory_; | 
 |     RtpHeaderExtensionMap extensions_; | 
 |   } test; | 
 |  | 
 |   RunBaseTest(&test); | 
 | } | 
 |  | 
 | TEST_F(VideoSendStreamTest, SupportsVideoRotation) { | 
 |   class VideoRotationObserver : public test::SendTest { | 
 |    public: | 
 |     VideoRotationObserver() : SendTest(kDefaultTimeoutMs) { | 
 |       extensions_.Register<VideoOrientation>(kVideoRotationExtensionId); | 
 |     } | 
 |  | 
 |     Action OnSendRtp(const uint8_t* packet, size_t length) override { | 
 |       RtpPacket rtp_packet(&extensions_); | 
 |       EXPECT_TRUE(rtp_packet.Parse(packet, length)); | 
 |       // Only the last packet of the frame is required to have the extension. | 
 |       if (!rtp_packet.Marker()) | 
 |         return SEND_PACKET; | 
 |       EXPECT_EQ(rtp_packet.GetExtension<VideoOrientation>(), kVideoRotation_90); | 
 |       observation_complete_.Set(); | 
 |       return SEND_PACKET; | 
 |     } | 
 |  | 
 |     void ModifyVideoConfigs( | 
 |         VideoSendStream::Config* send_config, | 
 |         std::vector<VideoReceiveStream::Config>* receive_configs, | 
 |         VideoEncoderConfig* encoder_config) override { | 
 |       send_config->rtp.extensions.clear(); | 
 |       send_config->rtp.extensions.push_back(RtpExtension( | 
 |           RtpExtension::kVideoRotationUri, kVideoRotationExtensionId)); | 
 |     } | 
 |  | 
 |     void OnFrameGeneratorCapturerCreated( | 
 |         test::FrameGeneratorCapturer* frame_generator_capturer) override { | 
 |       frame_generator_capturer->SetFakeRotation(kVideoRotation_90); | 
 |     } | 
 |  | 
 |     void PerformTest() override { | 
 |       EXPECT_TRUE(Wait()) << "Timed out while waiting for single RTP packet."; | 
 |     } | 
 |  | 
 |    private: | 
 |     RtpHeaderExtensionMap extensions_; | 
 |   } test; | 
 |  | 
 |   RunBaseTest(&test); | 
 | } | 
 |  | 
 | TEST_F(VideoSendStreamTest, SupportsVideoContentType) { | 
 |   class VideoContentTypeObserver : public test::SendTest { | 
 |    public: | 
 |     VideoContentTypeObserver() | 
 |         : SendTest(kDefaultTimeoutMs), first_frame_sent_(false) { | 
 |       extensions_.Register<VideoContentTypeExtension>( | 
 |           kVideoContentTypeExtensionId); | 
 |     } | 
 |  | 
 |     Action OnSendRtp(const uint8_t* packet, size_t length) override { | 
 |       RtpPacket rtp_packet(&extensions_); | 
 |       EXPECT_TRUE(rtp_packet.Parse(packet, length)); | 
 |       // Only the last packet of the key-frame must have extension. | 
 |       if (!rtp_packet.Marker() || first_frame_sent_) | 
 |         return SEND_PACKET; | 
 |       // First marker bit seen means that the first frame is sent. | 
 |       first_frame_sent_ = true; | 
 |       VideoContentType type; | 
 |       EXPECT_TRUE(rtp_packet.GetExtension<VideoContentTypeExtension>(&type)); | 
 |       EXPECT_TRUE(videocontenttypehelpers::IsScreenshare(type)); | 
 |       observation_complete_.Set(); | 
 |       return SEND_PACKET; | 
 |     } | 
 |  | 
 |     void ModifyVideoConfigs( | 
 |         VideoSendStream::Config* send_config, | 
 |         std::vector<VideoReceiveStream::Config>* receive_configs, | 
 |         VideoEncoderConfig* encoder_config) override { | 
 |       send_config->rtp.extensions.clear(); | 
 |       send_config->rtp.extensions.push_back(RtpExtension( | 
 |           RtpExtension::kVideoContentTypeUri, kVideoContentTypeExtensionId)); | 
 |       encoder_config->content_type = VideoEncoderConfig::ContentType::kScreen; | 
 |     } | 
 |  | 
 |     void PerformTest() override { | 
 |       EXPECT_TRUE(Wait()) << "Timed out while waiting for single RTP packet."; | 
 |     } | 
 |  | 
 |    private: | 
 |     bool first_frame_sent_; | 
 |     RtpHeaderExtensionMap extensions_; | 
 |   } test; | 
 |  | 
 |   RunBaseTest(&test); | 
 | } | 
 |  | 
 | TEST_F(VideoSendStreamTest, SupportsVideoTimingFrames) { | 
 |   class VideoTimingObserver : public test::SendTest { | 
 |    public: | 
 |     VideoTimingObserver() | 
 |         : SendTest(kDefaultTimeoutMs), first_frame_sent_(false) { | 
 |       extensions_.Register<VideoTimingExtension>(kVideoTimingExtensionId); | 
 |     } | 
 |  | 
 |     Action OnSendRtp(const uint8_t* packet, size_t length) override { | 
 |       RtpPacket rtp_packet(&extensions_); | 
 |       EXPECT_TRUE(rtp_packet.Parse(packet, length)); | 
 |       // Only the last packet of the frame must have extension. | 
 |       // Also don't check packets of the second frame if they happen to get | 
 |       // through before the test terminates. | 
 |       if (!rtp_packet.Marker() || first_frame_sent_) | 
 |         return SEND_PACKET; | 
 |       EXPECT_TRUE(rtp_packet.HasExtension<VideoTimingExtension>()); | 
 |       observation_complete_.Set(); | 
 |       first_frame_sent_ = true; | 
 |       return SEND_PACKET; | 
 |     } | 
 |  | 
 |     void ModifyVideoConfigs( | 
 |         VideoSendStream::Config* send_config, | 
 |         std::vector<VideoReceiveStream::Config>* receive_configs, | 
 |         VideoEncoderConfig* encoder_config) override { | 
 |       send_config->rtp.extensions.clear(); | 
 |       send_config->rtp.extensions.push_back( | 
 |           RtpExtension(RtpExtension::kVideoTimingUri, kVideoTimingExtensionId)); | 
 |     } | 
 |  | 
 |     void PerformTest() override { | 
 |       EXPECT_TRUE(Wait()) << "Timed out while waiting for timing frames."; | 
 |     } | 
 |  | 
 |    private: | 
 |     RtpHeaderExtensionMap extensions_; | 
 |     bool first_frame_sent_; | 
 |   } test; | 
 |  | 
 |   RunBaseTest(&test); | 
 | } | 
 |  | 
 | class FakeReceiveStatistics : public ReceiveStatisticsProvider { | 
 |  public: | 
 |   FakeReceiveStatistics(uint32_t send_ssrc, | 
 |                         uint32_t last_sequence_number, | 
 |                         uint32_t cumulative_lost, | 
 |                         uint8_t fraction_lost) { | 
 |     stat_.SetMediaSsrc(send_ssrc); | 
 |     stat_.SetExtHighestSeqNum(last_sequence_number); | 
 |     stat_.SetCumulativeLost(cumulative_lost); | 
 |     stat_.SetFractionLost(fraction_lost); | 
 |   } | 
 |  | 
 |   std::vector<rtcp::ReportBlock> RtcpReportBlocks(size_t max_blocks) override { | 
 |     EXPECT_GE(max_blocks, 1u); | 
 |     return {stat_}; | 
 |   } | 
 |  | 
 |  private: | 
 |   rtcp::ReportBlock stat_; | 
 | }; | 
 |  | 
 | class UlpfecObserver : public test::EndToEndTest { | 
 |  public: | 
 |   // Some of the test cases are expected to time out. | 
 |   // Use a shorter timeout window than the default one for those. | 
 |   static constexpr int kReducedTimeoutMs = 10000; | 
 |  | 
 |   UlpfecObserver(bool header_extensions_enabled, | 
 |                  bool use_nack, | 
 |                  bool expect_red, | 
 |                  bool expect_ulpfec, | 
 |                  const std::string& codec, | 
 |                  VideoEncoderFactory* encoder_factory) | 
 |       : EndToEndTest(expect_ulpfec ? VideoSendStreamTest::kDefaultTimeoutMs | 
 |                                    : kReducedTimeoutMs), | 
 |         encoder_factory_(encoder_factory), | 
 |         payload_name_(codec), | 
 |         use_nack_(use_nack), | 
 |         expect_red_(expect_red), | 
 |         expect_ulpfec_(expect_ulpfec), | 
 |         sent_media_(false), | 
 |         sent_ulpfec_(false), | 
 |         header_extensions_enabled_(header_extensions_enabled) { | 
 |     extensions_.Register<AbsoluteSendTime>(kAbsSendTimeExtensionId); | 
 |     extensions_.Register<TransportSequenceNumber>( | 
 |         kTransportSequenceNumberExtensionId); | 
 |   } | 
 |  | 
 |  private: | 
 |   Action OnSendRtp(const uint8_t* packet, size_t length) override { | 
 |     RtpPacket rtp_packet(&extensions_); | 
 |     EXPECT_TRUE(rtp_packet.Parse(packet, length)); | 
 |  | 
 |     int encapsulated_payload_type = -1; | 
 |     if (rtp_packet.PayloadType() == VideoSendStreamTest::kRedPayloadType) { | 
 |       EXPECT_TRUE(expect_red_); | 
 |       encapsulated_payload_type = rtp_packet.payload()[0]; | 
 |       if (encapsulated_payload_type != | 
 |           VideoSendStreamTest::kFakeVideoSendPayloadType) { | 
 |         EXPECT_EQ(VideoSendStreamTest::kUlpfecPayloadType, | 
 |                   encapsulated_payload_type); | 
 |       } | 
 |     } else { | 
 |       EXPECT_EQ(VideoSendStreamTest::kFakeVideoSendPayloadType, | 
 |                 rtp_packet.PayloadType()); | 
 |       if (rtp_packet.payload_size() > 0) { | 
 |         // Not padding-only, media received outside of RED. | 
 |         EXPECT_FALSE(expect_red_); | 
 |         sent_media_ = true; | 
 |       } | 
 |     } | 
 |  | 
 |     if (header_extensions_enabled_) { | 
 |       uint32_t abs_send_time; | 
 |       EXPECT_TRUE(rtp_packet.GetExtension<AbsoluteSendTime>(&abs_send_time)); | 
 |       uint16_t transport_seq_num; | 
 |       EXPECT_TRUE( | 
 |           rtp_packet.GetExtension<TransportSequenceNumber>(&transport_seq_num)); | 
 |       if (!first_packet_) { | 
 |         uint32_t kHalf24BitsSpace = 0xFFFFFF / 2; | 
 |         if (abs_send_time <= kHalf24BitsSpace && | 
 |             prev_abs_send_time_ > kHalf24BitsSpace) { | 
 |           // 24 bits wrap. | 
 |           EXPECT_GT(prev_abs_send_time_, abs_send_time); | 
 |         } else { | 
 |           EXPECT_GE(abs_send_time, prev_abs_send_time_); | 
 |         } | 
 |  | 
 |         uint16_t seq_num_diff = transport_seq_num - prev_transport_seq_num_; | 
 |         EXPECT_EQ(1, seq_num_diff); | 
 |       } | 
 |       first_packet_ = false; | 
 |       prev_abs_send_time_ = abs_send_time; | 
 |       prev_transport_seq_num_ = transport_seq_num; | 
 |     } | 
 |  | 
 |     if (encapsulated_payload_type != -1) { | 
 |       if (encapsulated_payload_type == | 
 |           VideoSendStreamTest::kUlpfecPayloadType) { | 
 |         EXPECT_TRUE(expect_ulpfec_); | 
 |         sent_ulpfec_ = true; | 
 |       } else { | 
 |         sent_media_ = true; | 
 |       } | 
 |     } | 
 |  | 
 |     if (sent_media_ && sent_ulpfec_) { | 
 |       observation_complete_.Set(); | 
 |     } | 
 |  | 
 |     return SEND_PACKET; | 
 |   } | 
 |  | 
 |   std::unique_ptr<test::PacketTransport> CreateSendTransport( | 
 |       TaskQueueBase* task_queue, | 
 |       Call* sender_call) override { | 
 |     // At low RTT (< kLowRttNackMs) -> NACK only, no FEC. | 
 |     // Configure some network delay. | 
 |     const int kNetworkDelayMs = 100; | 
 |     BuiltInNetworkBehaviorConfig config; | 
 |     config.loss_percent = 5; | 
 |     config.queue_delay_ms = kNetworkDelayMs; | 
 |     return std::make_unique<test::PacketTransport>( | 
 |         task_queue, sender_call, this, test::PacketTransport::kSender, | 
 |         VideoSendStreamTest::payload_type_map_, | 
 |         std::make_unique<FakeNetworkPipe>( | 
 |             Clock::GetRealTimeClock(), | 
 |             std::make_unique<SimulatedNetwork>(config))); | 
 |   } | 
 |  | 
 |   void ModifyVideoConfigs( | 
 |       VideoSendStream::Config* send_config, | 
 |       std::vector<VideoReceiveStream::Config>* receive_configs, | 
 |       VideoEncoderConfig* encoder_config) override { | 
 |     if (use_nack_) { | 
 |       send_config->rtp.nack.rtp_history_ms = | 
 |           (*receive_configs)[0].rtp.nack.rtp_history_ms = | 
 |               VideoSendStreamTest::kNackRtpHistoryMs; | 
 |     } | 
 |     send_config->encoder_settings.encoder_factory = encoder_factory_; | 
 |     send_config->rtp.payload_name = payload_name_; | 
 |     send_config->rtp.ulpfec.red_payload_type = | 
 |         VideoSendStreamTest::kRedPayloadType; | 
 |     send_config->rtp.ulpfec.ulpfec_payload_type = | 
 |         VideoSendStreamTest::kUlpfecPayloadType; | 
 |     if (!header_extensions_enabled_) { | 
 |       send_config->rtp.extensions.clear(); | 
 |     } else { | 
 |       send_config->rtp.extensions.push_back( | 
 |           RtpExtension(RtpExtension::kAbsSendTimeUri, kAbsSendTimeExtensionId)); | 
 |     } | 
 |     (*receive_configs)[0].rtp.extensions = send_config->rtp.extensions; | 
 |     encoder_config->codec_type = PayloadStringToCodecType(payload_name_); | 
 |     (*receive_configs)[0].rtp.red_payload_type = | 
 |         send_config->rtp.ulpfec.red_payload_type; | 
 |     (*receive_configs)[0].rtp.ulpfec_payload_type = | 
 |         send_config->rtp.ulpfec.ulpfec_payload_type; | 
 |   } | 
 |  | 
 |   void PerformTest() override { | 
 |     EXPECT_EQ(expect_ulpfec_, Wait()) | 
 |         << "Timed out waiting for ULPFEC and/or media packets."; | 
 |   } | 
 |  | 
 |   VideoEncoderFactory* encoder_factory_; | 
 |   RtpHeaderExtensionMap extensions_; | 
 |   const std::string payload_name_; | 
 |   const bool use_nack_; | 
 |   const bool expect_red_; | 
 |   const bool expect_ulpfec_; | 
 |   bool sent_media_; | 
 |   bool sent_ulpfec_; | 
 |   const bool header_extensions_enabled_; | 
 |   bool first_packet_ = true; | 
 |   uint32_t prev_abs_send_time_ = 0; | 
 |   uint16_t prev_transport_seq_num_ = 0; | 
 | }; | 
 |  | 
 | TEST_F(VideoSendStreamTest, SupportsUlpfecWithExtensions) { | 
 |   test::FunctionVideoEncoderFactory encoder_factory( | 
 |       []() { return VP8Encoder::Create(); }); | 
 |   UlpfecObserver test(true, false, true, true, "VP8", &encoder_factory); | 
 |   RunBaseTest(&test); | 
 | } | 
 |  | 
 | TEST_F(VideoSendStreamTest, SupportsUlpfecWithoutExtensions) { | 
 |   test::FunctionVideoEncoderFactory encoder_factory( | 
 |       []() { return VP8Encoder::Create(); }); | 
 |   UlpfecObserver test(false, false, true, true, "VP8", &encoder_factory); | 
 |   RunBaseTest(&test); | 
 | } | 
 |  | 
 | class VideoSendStreamWithoutUlpfecTest : public test::CallTest { | 
 |  protected: | 
 |   VideoSendStreamWithoutUlpfecTest() | 
 |       : field_trial_(field_trials_, "WebRTC-DisableUlpFecExperiment/Enabled/") { | 
 |   } | 
 |  | 
 |   test::ScopedKeyValueConfig field_trial_; | 
 | }; | 
 |  | 
 | TEST_F(VideoSendStreamWithoutUlpfecTest, NoUlpfecIfDisabledThroughFieldTrial) { | 
 |   test::FunctionVideoEncoderFactory encoder_factory( | 
 |       []() { return VP8Encoder::Create(); }); | 
 |   UlpfecObserver test(false, false, false, false, "VP8", &encoder_factory); | 
 |   RunBaseTest(&test); | 
 | } | 
 |  | 
 | // The FEC scheme used is not efficient for H264, so we should not use RED/FEC | 
 | // since we'll still have to re-request FEC packets, effectively wasting | 
 | // bandwidth since the receiver has to wait for FEC retransmissions to determine | 
 | // that the received state is actually decodable. | 
 | TEST_F(VideoSendStreamTest, DoesNotUtilizeUlpfecForH264WithNackEnabled) { | 
 |   test::FunctionVideoEncoderFactory encoder_factory([]() { | 
 |     return std::make_unique<test::FakeH264Encoder>(Clock::GetRealTimeClock()); | 
 |   }); | 
 |   UlpfecObserver test(false, true, false, false, "H264", &encoder_factory); | 
 |   RunBaseTest(&test); | 
 | } | 
 |  | 
 | // Without retransmissions FEC for H264 is fine. | 
 | TEST_F(VideoSendStreamTest, DoesUtilizeUlpfecForH264WithoutNackEnabled) { | 
 |   test::FunctionVideoEncoderFactory encoder_factory([]() { | 
 |     return std::make_unique<test::FakeH264Encoder>(Clock::GetRealTimeClock()); | 
 |   }); | 
 |   UlpfecObserver test(false, false, true, true, "H264", &encoder_factory); | 
 |   RunBaseTest(&test); | 
 | } | 
 |  | 
 | TEST_F(VideoSendStreamTest, DoesUtilizeUlpfecForVp8WithNackEnabled) { | 
 |   test::FunctionVideoEncoderFactory encoder_factory( | 
 |       []() { return VP8Encoder::Create(); }); | 
 |   UlpfecObserver test(false, true, true, true, "VP8", &encoder_factory); | 
 |   RunBaseTest(&test); | 
 | } | 
 |  | 
 | #if defined(RTC_ENABLE_VP9) | 
 | TEST_F(VideoSendStreamTest, DoesUtilizeUlpfecForVp9WithNackEnabled) { | 
 |   test::FunctionVideoEncoderFactory encoder_factory( | 
 |       []() { return VP9Encoder::Create(); }); | 
 |   UlpfecObserver test(false, true, true, true, "VP9", &encoder_factory); | 
 |   RunBaseTest(&test); | 
 | } | 
 | #endif  // defined(RTC_ENABLE_VP9) | 
 |  | 
 | TEST_F(VideoSendStreamTest, SupportsUlpfecWithMultithreadedH264) { | 
 |   std::unique_ptr<TaskQueueFactory> task_queue_factory = | 
 |       CreateDefaultTaskQueueFactory(); | 
 |   test::FunctionVideoEncoderFactory encoder_factory([&]() { | 
 |     return std::make_unique<test::MultithreadedFakeH264Encoder>( | 
 |         Clock::GetRealTimeClock(), task_queue_factory.get()); | 
 |   }); | 
 |   UlpfecObserver test(false, false, true, true, "H264", &encoder_factory); | 
 |   RunBaseTest(&test); | 
 | } | 
 |  | 
 | // TODO(brandtr): Move these FlexFEC tests when we have created | 
 | // FlexfecSendStream. | 
 | class FlexfecObserver : public test::EndToEndTest { | 
 |  public: | 
 |   FlexfecObserver(bool header_extensions_enabled, | 
 |                   bool use_nack, | 
 |                   const std::string& codec, | 
 |                   VideoEncoderFactory* encoder_factory, | 
 |                   size_t num_video_streams) | 
 |       : EndToEndTest(VideoSendStreamTest::kDefaultTimeoutMs), | 
 |         encoder_factory_(encoder_factory), | 
 |         payload_name_(codec), | 
 |         use_nack_(use_nack), | 
 |         sent_media_(false), | 
 |         sent_flexfec_(false), | 
 |         header_extensions_enabled_(header_extensions_enabled), | 
 |         num_video_streams_(num_video_streams) { | 
 |     extensions_.Register<AbsoluteSendTime>(kAbsSendTimeExtensionId); | 
 |     extensions_.Register<TransmissionOffset>(kTimestampOffsetExtensionId); | 
 |     extensions_.Register<TransportSequenceNumber>( | 
 |         kTransportSequenceNumberExtensionId); | 
 |   } | 
 |  | 
 |   size_t GetNumFlexfecStreams() const override { return 1; } | 
 |   size_t GetNumVideoStreams() const override { return num_video_streams_; } | 
 |  | 
 |  private: | 
 |   Action OnSendRtp(const uint8_t* packet, size_t length) override { | 
 |     RtpPacket rtp_packet(&extensions_); | 
 |     EXPECT_TRUE(rtp_packet.Parse(packet, length)); | 
 |  | 
 |     if (rtp_packet.PayloadType() == VideoSendStreamTest::kFlexfecPayloadType) { | 
 |       EXPECT_EQ(VideoSendStreamTest::kFlexfecSendSsrc, rtp_packet.Ssrc()); | 
 |       sent_flexfec_ = true; | 
 |     } else { | 
 |       EXPECT_EQ(VideoSendStreamTest::kFakeVideoSendPayloadType, | 
 |                 rtp_packet.PayloadType()); | 
 |       EXPECT_THAT(::testing::make_tuple(VideoSendStreamTest::kVideoSendSsrcs, | 
 |                                         num_video_streams_), | 
 |                   ::testing::Contains(rtp_packet.Ssrc())); | 
 |       sent_media_ = true; | 
 |     } | 
 |  | 
 |     if (header_extensions_enabled_) { | 
 |       EXPECT_TRUE(rtp_packet.HasExtension<AbsoluteSendTime>()); | 
 |       EXPECT_TRUE(rtp_packet.HasExtension<TransmissionOffset>()); | 
 |       EXPECT_TRUE(rtp_packet.HasExtension<TransportSequenceNumber>()); | 
 |     } | 
 |  | 
 |     if (sent_media_ && sent_flexfec_) { | 
 |       observation_complete_.Set(); | 
 |     } | 
 |  | 
 |     return SEND_PACKET; | 
 |   } | 
 |  | 
 |   std::unique_ptr<test::PacketTransport> CreateSendTransport( | 
 |       TaskQueueBase* task_queue, | 
 |       Call* sender_call) override { | 
 |     // At low RTT (< kLowRttNackMs) -> NACK only, no FEC. | 
 |     // Therefore we need some network delay. | 
 |     const int kNetworkDelayMs = 100; | 
 |     BuiltInNetworkBehaviorConfig config; | 
 |     config.loss_percent = 5; | 
 |     config.queue_delay_ms = kNetworkDelayMs; | 
 |     return std::make_unique<test::PacketTransport>( | 
 |         task_queue, sender_call, this, test::PacketTransport::kSender, | 
 |         VideoSendStreamTest::payload_type_map_, | 
 |         std::make_unique<FakeNetworkPipe>( | 
 |             Clock::GetRealTimeClock(), | 
 |             std::make_unique<SimulatedNetwork>(config))); | 
 |   } | 
 |  | 
 |   std::unique_ptr<test::PacketTransport> CreateReceiveTransport( | 
 |       TaskQueueBase* task_queue) override { | 
 |     // We need the RTT to be >200 ms to send FEC and the network delay for the | 
 |     // send transport is 100 ms, so add 100 ms (but no loss) on the return link. | 
 |     BuiltInNetworkBehaviorConfig config; | 
 |     config.loss_percent = 0; | 
 |     config.queue_delay_ms = 100; | 
 |     return std::make_unique<test::PacketTransport>( | 
 |         task_queue, nullptr, this, test::PacketTransport::kReceiver, | 
 |         VideoSendStreamTest::payload_type_map_, | 
 |         std::make_unique<FakeNetworkPipe>( | 
 |             Clock::GetRealTimeClock(), | 
 |             std::make_unique<SimulatedNetwork>(config))); | 
 |   } | 
 |  | 
 |   void ModifyVideoConfigs( | 
 |       VideoSendStream::Config* send_config, | 
 |       std::vector<VideoReceiveStream::Config>* receive_configs, | 
 |       VideoEncoderConfig* encoder_config) override { | 
 |     if (use_nack_) { | 
 |       send_config->rtp.nack.rtp_history_ms = | 
 |           (*receive_configs)[0].rtp.nack.rtp_history_ms = | 
 |               VideoSendStreamTest::kNackRtpHistoryMs; | 
 |     } | 
 |     send_config->encoder_settings.encoder_factory = encoder_factory_; | 
 |     send_config->rtp.payload_name = payload_name_; | 
 |     if (header_extensions_enabled_) { | 
 |       send_config->rtp.extensions.push_back( | 
 |           RtpExtension(RtpExtension::kAbsSendTimeUri, kAbsSendTimeExtensionId)); | 
 |       send_config->rtp.extensions.push_back(RtpExtension( | 
 |           RtpExtension::kTimestampOffsetUri, kTimestampOffsetExtensionId)); | 
 |     } else { | 
 |       send_config->rtp.extensions.clear(); | 
 |     } | 
 |     (*receive_configs)[0].rtp.extensions = send_config->rtp.extensions; | 
 |     encoder_config->codec_type = PayloadStringToCodecType(payload_name_); | 
 |   } | 
 |  | 
 |   void PerformTest() override { | 
 |     EXPECT_TRUE(Wait()) | 
 |         << "Timed out waiting for FlexFEC and/or media packets."; | 
 |   } | 
 |  | 
 |   VideoEncoderFactory* encoder_factory_; | 
 |   RtpHeaderExtensionMap extensions_; | 
 |   const std::string payload_name_; | 
 |   const bool use_nack_; | 
 |   bool sent_media_; | 
 |   bool sent_flexfec_; | 
 |   const bool header_extensions_enabled_; | 
 |   const size_t num_video_streams_; | 
 | }; | 
 |  | 
 | TEST_F(VideoSendStreamTest, SupportsFlexfecVp8) { | 
 |   test::FunctionVideoEncoderFactory encoder_factory( | 
 |       []() { return VP8Encoder::Create(); }); | 
 |   FlexfecObserver test(false, false, "VP8", &encoder_factory, 1); | 
 |   RunBaseTest(&test); | 
 | } | 
 |  | 
 | TEST_F(VideoSendStreamTest, SupportsFlexfecSimulcastVp8) { | 
 |   test::FunctionVideoEncoderFactory encoder_factory( | 
 |       []() { return VP8Encoder::Create(); }); | 
 |   FlexfecObserver test(false, false, "VP8", &encoder_factory, 2); | 
 |   RunBaseTest(&test); | 
 | } | 
 |  | 
 | TEST_F(VideoSendStreamTest, SupportsFlexfecWithNackVp8) { | 
 |   test::FunctionVideoEncoderFactory encoder_factory( | 
 |       []() { return VP8Encoder::Create(); }); | 
 |   FlexfecObserver test(false, true, "VP8", &encoder_factory, 1); | 
 |   RunBaseTest(&test); | 
 | } | 
 |  | 
 | TEST_F(VideoSendStreamTest, SupportsFlexfecWithRtpExtensionsVp8) { | 
 |   test::FunctionVideoEncoderFactory encoder_factory( | 
 |       []() { return VP8Encoder::Create(); }); | 
 |   FlexfecObserver test(true, false, "VP8", &encoder_factory, 1); | 
 |   RunBaseTest(&test); | 
 | } | 
 |  | 
 | #if defined(RTC_ENABLE_VP9) | 
 | TEST_F(VideoSendStreamTest, SupportsFlexfecVp9) { | 
 |   test::FunctionVideoEncoderFactory encoder_factory( | 
 |       []() { return VP9Encoder::Create(); }); | 
 |   FlexfecObserver test(false, false, "VP9", &encoder_factory, 1); | 
 |   RunBaseTest(&test); | 
 | } | 
 |  | 
 | TEST_F(VideoSendStreamTest, SupportsFlexfecWithNackVp9) { | 
 |   test::FunctionVideoEncoderFactory encoder_factory( | 
 |       []() { return VP9Encoder::Create(); }); | 
 |   FlexfecObserver test(false, true, "VP9", &encoder_factory, 1); | 
 |   RunBaseTest(&test); | 
 | } | 
 | #endif  // defined(RTC_ENABLE_VP9) | 
 |  | 
 | TEST_F(VideoSendStreamTest, SupportsFlexfecH264) { | 
 |   test::FunctionVideoEncoderFactory encoder_factory([]() { | 
 |     return std::make_unique<test::FakeH264Encoder>(Clock::GetRealTimeClock()); | 
 |   }); | 
 |   FlexfecObserver test(false, false, "H264", &encoder_factory, 1); | 
 |   RunBaseTest(&test); | 
 | } | 
 |  | 
 | TEST_F(VideoSendStreamTest, SupportsFlexfecWithNackH264) { | 
 |   test::FunctionVideoEncoderFactory encoder_factory([]() { | 
 |     return std::make_unique<test::FakeH264Encoder>(Clock::GetRealTimeClock()); | 
 |   }); | 
 |   FlexfecObserver test(false, true, "H264", &encoder_factory, 1); | 
 |   RunBaseTest(&test); | 
 | } | 
 |  | 
 | TEST_F(VideoSendStreamTest, SupportsFlexfecWithMultithreadedH264) { | 
 |   std::unique_ptr<TaskQueueFactory> task_queue_factory = | 
 |       CreateDefaultTaskQueueFactory(); | 
 |   test::FunctionVideoEncoderFactory encoder_factory([&]() { | 
 |     return std::make_unique<test::MultithreadedFakeH264Encoder>( | 
 |         Clock::GetRealTimeClock(), task_queue_factory.get()); | 
 |   }); | 
 |  | 
 |   FlexfecObserver test(false, false, "H264", &encoder_factory, 1); | 
 |   RunBaseTest(&test); | 
 | } | 
 |  | 
 | void VideoSendStreamTest::TestNackRetransmission( | 
 |     uint32_t retransmit_ssrc, | 
 |     uint8_t retransmit_payload_type) { | 
 |   class NackObserver : public test::SendTest { | 
 |    public: | 
 |     explicit NackObserver(uint32_t retransmit_ssrc, | 
 |                           uint8_t retransmit_payload_type) | 
 |         : SendTest(kDefaultTimeoutMs), | 
 |           send_count_(0), | 
 |           retransmit_count_(0), | 
 |           retransmit_ssrc_(retransmit_ssrc), | 
 |           retransmit_payload_type_(retransmit_payload_type) {} | 
 |  | 
 |    private: | 
 |     Action OnSendRtp(const uint8_t* packet, size_t length) override { | 
 |       RtpPacket rtp_packet; | 
 |       EXPECT_TRUE(rtp_packet.Parse(packet, length)); | 
 |  | 
 |       // NACK packets two times at some arbitrary points. | 
 |       const int kNackedPacketsAtOnceCount = 3; | 
 |       const int kRetransmitTarget = kNackedPacketsAtOnceCount * 2; | 
 |  | 
 |       // Skip padding packets because they will never be retransmitted. | 
 |       if (rtp_packet.payload_size() == 0) { | 
 |         return SEND_PACKET; | 
 |       } | 
 |  | 
 |       ++send_count_; | 
 |  | 
 |       // NACK packets at arbitrary points. | 
 |       if (send_count_ % 25 == 0) { | 
 |         RTCPSender::Configuration config; | 
 |         config.clock = Clock::GetRealTimeClock(); | 
 |         config.outgoing_transport = transport_adapter_.get(); | 
 |         config.rtcp_report_interval = TimeDelta::Millis(kRtcpIntervalMs); | 
 |         config.local_media_ssrc = kReceiverLocalVideoSsrc; | 
 |         RTCPSender rtcp_sender(config); | 
 |  | 
 |         rtcp_sender.SetRTCPStatus(RtcpMode::kReducedSize); | 
 |         rtcp_sender.SetRemoteSSRC(kVideoSendSsrcs[0]); | 
 |  | 
 |         RTCPSender::FeedbackState feedback_state; | 
 |         uint16_t nack_sequence_numbers[kNackedPacketsAtOnceCount]; | 
 |         int nack_count = 0; | 
 |         for (uint16_t sequence_number : | 
 |              sequence_numbers_pending_retransmission_) { | 
 |           if (nack_count < kNackedPacketsAtOnceCount) { | 
 |             nack_sequence_numbers[nack_count++] = sequence_number; | 
 |           } else { | 
 |             break; | 
 |           } | 
 |         } | 
 |  | 
 |         EXPECT_EQ(0, rtcp_sender.SendRTCP(feedback_state, kRtcpNack, nack_count, | 
 |                                           nack_sequence_numbers)); | 
 |       } | 
 |  | 
 |       uint16_t sequence_number = rtp_packet.SequenceNumber(); | 
 |       if (rtp_packet.Ssrc() == retransmit_ssrc_ && | 
 |           retransmit_ssrc_ != kVideoSendSsrcs[0]) { | 
 |         // Not kVideoSendSsrcs[0], assume correct RTX packet. Extract sequence | 
 |         // number. | 
 |         const uint8_t* rtx_header = rtp_packet.payload().data(); | 
 |         sequence_number = (rtx_header[0] << 8) + rtx_header[1]; | 
 |       } | 
 |  | 
 |       auto it = sequence_numbers_pending_retransmission_.find(sequence_number); | 
 |       if (it == sequence_numbers_pending_retransmission_.end()) { | 
 |         // Not currently pending retransmission. Add it to retransmission queue | 
 |         // if media and limit not reached. | 
 |         if (rtp_packet.Ssrc() == kVideoSendSsrcs[0] && | 
 |             rtp_packet.payload_size() > 0 && | 
 |             retransmit_count_ + | 
 |                     sequence_numbers_pending_retransmission_.size() < | 
 |                 kRetransmitTarget) { | 
 |           sequence_numbers_pending_retransmission_.insert(sequence_number); | 
 |         } | 
 |       } else { | 
 |         // Packet is a retransmission, remove it from queue and check if done. | 
 |         sequence_numbers_pending_retransmission_.erase(it); | 
 |         if (++retransmit_count_ == kRetransmitTarget) { | 
 |           EXPECT_EQ(retransmit_ssrc_, rtp_packet.Ssrc()); | 
 |           EXPECT_EQ(retransmit_payload_type_, rtp_packet.PayloadType()); | 
 |           observation_complete_.Set(); | 
 |         } | 
 |       } | 
 |  | 
 |       return SEND_PACKET; | 
 |     } | 
 |  | 
 |     void ModifyVideoConfigs( | 
 |         VideoSendStream::Config* send_config, | 
 |         std::vector<VideoReceiveStream::Config>* receive_configs, | 
 |         VideoEncoderConfig* encoder_config) override { | 
 |       transport_adapter_.reset( | 
 |           new internal::TransportAdapter(send_config->send_transport)); | 
 |       transport_adapter_->Enable(); | 
 |       send_config->rtp.nack.rtp_history_ms = kNackRtpHistoryMs; | 
 |       send_config->rtp.rtx.payload_type = retransmit_payload_type_; | 
 |       if (retransmit_ssrc_ != kVideoSendSsrcs[0]) | 
 |         send_config->rtp.rtx.ssrcs.push_back(retransmit_ssrc_); | 
 |     } | 
 |  | 
 |     void PerformTest() override { | 
 |       EXPECT_TRUE(Wait()) << "Timed out while waiting for NACK retransmission."; | 
 |     } | 
 |  | 
 |     std::unique_ptr<internal::TransportAdapter> transport_adapter_; | 
 |     int send_count_; | 
 |     int retransmit_count_; | 
 |     const uint32_t retransmit_ssrc_; | 
 |     const uint8_t retransmit_payload_type_; | 
 |     std::set<uint16_t> sequence_numbers_pending_retransmission_; | 
 |   } test(retransmit_ssrc, retransmit_payload_type); | 
 |  | 
 |   RunBaseTest(&test); | 
 | } | 
 |  | 
 | TEST_F(VideoSendStreamTest, RetransmitsNack) { | 
 |   // Normal NACKs should use the send SSRC. | 
 |   TestNackRetransmission(kVideoSendSsrcs[0], kFakeVideoSendPayloadType); | 
 | } | 
 |  | 
 | TEST_F(VideoSendStreamTest, RetransmitsNackOverRtx) { | 
 |   // NACKs over RTX should use a separate SSRC. | 
 |   TestNackRetransmission(kSendRtxSsrcs[0], kSendRtxPayloadType); | 
 | } | 
 |  | 
 | void VideoSendStreamTest::TestPacketFragmentationSize(VideoFormat format, | 
 |                                                       bool with_fec) { | 
 |   // Use a fake encoder to output a frame of every size in the range [90, 290], | 
 |   // for each size making sure that the exact number of payload bytes received | 
 |   // is correct and that packets are fragmented to respect max packet size. | 
 |   static const size_t kMaxPacketSize = 128; | 
 |   static const size_t start = 90; | 
 |   static const size_t stop = 290; | 
 |  | 
 |   // Observer that verifies that the expected number of packets and bytes | 
 |   // arrive for each frame size, from start_size to stop_size. | 
 |   class FrameFragmentationTest : public test::SendTest { | 
 |    public: | 
 |     FrameFragmentationTest(size_t max_packet_size, | 
 |                            size_t start_size, | 
 |                            size_t stop_size, | 
 |                            bool test_generic_packetization, | 
 |                            bool use_fec) | 
 |         : SendTest(kLongTimeoutMs), | 
 |           encoder_(stop), | 
 |           encoder_factory_(&encoder_), | 
 |           max_packet_size_(max_packet_size), | 
 |           stop_size_(stop_size), | 
 |           test_generic_packetization_(test_generic_packetization), | 
 |           use_fec_(use_fec), | 
 |           packet_count_(0), | 
 |           packets_lost_(0), | 
 |           last_packet_count_(0), | 
 |           last_packets_lost_(0), | 
 |           accumulated_size_(0), | 
 |           accumulated_payload_(0), | 
 |           fec_packet_received_(false), | 
 |           current_size_rtp_(start_size), | 
 |           current_size_frame_(static_cast<int>(start_size)) { | 
 |       // Fragmentation required, this test doesn't make sense without it. | 
 |       encoder_.SetFrameSize(start_size); | 
 |       RTC_DCHECK_GT(stop_size, max_packet_size); | 
 |       if (!test_generic_packetization_) | 
 |         encoder_.SetCodecType(kVideoCodecVP8); | 
 |     } | 
 |  | 
 |    private: | 
 |     Action OnSendRtp(const uint8_t* packet, size_t size) override { | 
 |       size_t length = size; | 
 |       RtpPacket rtp_packet; | 
 |       EXPECT_TRUE(rtp_packet.Parse(packet, length)); | 
 |  | 
 |       EXPECT_LE(length, max_packet_size_); | 
 |  | 
 |       if (use_fec_ && rtp_packet.payload_size() > 0) { | 
 |         uint8_t payload_type = rtp_packet.payload()[0]; | 
 |         bool is_fec = rtp_packet.PayloadType() == kRedPayloadType && | 
 |                       payload_type == kUlpfecPayloadType; | 
 |         if (is_fec) { | 
 |           fec_packet_received_ = true; | 
 |           return SEND_PACKET; | 
 |         } | 
 |       } | 
 |  | 
 |       accumulated_size_ += length; | 
 |  | 
 |       if (use_fec_) | 
 |         TriggerLossReport(rtp_packet); | 
 |  | 
 |       if (test_generic_packetization_) { | 
 |         size_t overhead = rtp_packet.headers_size() + rtp_packet.padding_size(); | 
 |         // Only remove payload header and RED header if the packet actually | 
 |         // contains payload. | 
 |         if (length > overhead) { | 
 |           overhead += (1 /* Generic header */); | 
 |           if (use_fec_) | 
 |             overhead += 1;  // RED for FEC header. | 
 |         } | 
 |         EXPECT_GE(length, overhead); | 
 |         accumulated_payload_ += length - overhead; | 
 |       } | 
 |  | 
 |       // Marker bit set indicates last packet of a frame. | 
 |       if (rtp_packet.Marker()) { | 
 |         if (use_fec_ && accumulated_payload_ == current_size_rtp_ - 1) { | 
 |           // With FEC enabled, frame size is incremented asynchronously, so | 
 |           // "old" frames one byte too small may arrive. Accept, but don't | 
 |           // increase expected frame size. | 
 |           accumulated_size_ = 0; | 
 |           accumulated_payload_ = 0; | 
 |           return SEND_PACKET; | 
 |         } | 
 |  | 
 |         EXPECT_GE(accumulated_size_, current_size_rtp_); | 
 |         if (test_generic_packetization_) { | 
 |           EXPECT_EQ(current_size_rtp_, accumulated_payload_); | 
 |         } | 
 |  | 
 |         // Last packet of frame; reset counters. | 
 |         accumulated_size_ = 0; | 
 |         accumulated_payload_ = 0; | 
 |         if (current_size_rtp_ == stop_size_) { | 
 |           // Done! (Don't increase size again, might arrive more @ stop_size). | 
 |           observation_complete_.Set(); | 
 |         } else { | 
 |           // Increase next expected frame size. If testing with FEC, make sure | 
 |           // a FEC packet has been received for this frame size before | 
 |           // proceeding, to make sure that redundancy packets don't exceed | 
 |           // size limit. | 
 |           if (!use_fec_) { | 
 |             ++current_size_rtp_; | 
 |           } else if (fec_packet_received_) { | 
 |             fec_packet_received_ = false; | 
 |             ++current_size_rtp_; | 
 |  | 
 |             MutexLock lock(&mutex_); | 
 |             ++current_size_frame_; | 
 |           } | 
 |         } | 
 |       } | 
 |  | 
 |       return SEND_PACKET; | 
 |     } | 
 |  | 
 |     void TriggerLossReport(const RtpPacket& rtp_packet) { | 
 |       // Send lossy receive reports to trigger FEC enabling. | 
 |       const int kLossPercent = 5; | 
 |       if (++packet_count_ % (100 / kLossPercent) == 0) { | 
 |         packets_lost_++; | 
 |         int loss_delta = packets_lost_ - last_packets_lost_; | 
 |         int packets_delta = packet_count_ - last_packet_count_; | 
 |         last_packet_count_ = packet_count_; | 
 |         last_packets_lost_ = packets_lost_; | 
 |         uint8_t loss_ratio = | 
 |             static_cast<uint8_t>(loss_delta * 255 / packets_delta); | 
 |         FakeReceiveStatistics lossy_receive_stats( | 
 |             kVideoSendSsrcs[0], rtp_packet.SequenceNumber(), | 
 |             packets_lost_,  // Cumulative lost. | 
 |             loss_ratio);    // Loss percent. | 
 |         RTCPSender::Configuration config; | 
 |         config.clock = Clock::GetRealTimeClock(); | 
 |         config.receive_statistics = &lossy_receive_stats; | 
 |         config.outgoing_transport = transport_adapter_.get(); | 
 |         config.rtcp_report_interval = TimeDelta::Millis(kRtcpIntervalMs); | 
 |         config.local_media_ssrc = kVideoSendSsrcs[0]; | 
 |         RTCPSender rtcp_sender(config); | 
 |  | 
 |         rtcp_sender.SetRTCPStatus(RtcpMode::kReducedSize); | 
 |         rtcp_sender.SetRemoteSSRC(kVideoSendSsrcs[0]); | 
 |  | 
 |         RTCPSender::FeedbackState feedback_state; | 
 |  | 
 |         EXPECT_EQ(0, rtcp_sender.SendRTCP(feedback_state, kRtcpRr)); | 
 |       } | 
 |     } | 
 |  | 
 |     void UpdateConfiguration() { | 
 |       MutexLock lock(&mutex_); | 
 |       // Increase frame size for next encoded frame, in the context of the | 
 |       // encoder thread. | 
 |       if (!use_fec_ && current_size_frame_ < static_cast<int32_t>(stop_size_)) { | 
 |         ++current_size_frame_; | 
 |       } | 
 |       encoder_.SetFrameSize(static_cast<size_t>(current_size_frame_)); | 
 |     } | 
 |     void ModifySenderBitrateConfig( | 
 |         BitrateConstraints* bitrate_config) override { | 
 |       const int kMinBitrateBps = 300000; | 
 |       bitrate_config->min_bitrate_bps = kMinBitrateBps; | 
 |     } | 
 |  | 
 |     void ModifyVideoConfigs( | 
 |         VideoSendStream::Config* send_config, | 
 |         std::vector<VideoReceiveStream::Config>* receive_configs, | 
 |         VideoEncoderConfig* encoder_config) override { | 
 |       transport_adapter_.reset( | 
 |           new internal::TransportAdapter(send_config->send_transport)); | 
 |       transport_adapter_->Enable(); | 
 |       if (use_fec_) { | 
 |         send_config->rtp.ulpfec.red_payload_type = kRedPayloadType; | 
 |         send_config->rtp.ulpfec.ulpfec_payload_type = kUlpfecPayloadType; | 
 |       } | 
 |  | 
 |       if (!test_generic_packetization_) | 
 |         send_config->rtp.payload_name = "VP8"; | 
 |  | 
 |       send_config->encoder_settings.encoder_factory = &encoder_factory_; | 
 |       send_config->rtp.max_packet_size = kMaxPacketSize; | 
 |       encoder_.RegisterPostEncodeCallback([this]() { UpdateConfiguration(); }); | 
 |  | 
 |       // Make sure there is at least one extension header, to make the RTP | 
 |       // header larger than the base length of 12 bytes. | 
 |       EXPECT_FALSE(send_config->rtp.extensions.empty()); | 
 |  | 
 |       // Setup screen content disables frame dropping which makes this easier. | 
 |       EXPECT_EQ(1u, encoder_config->simulcast_layers.size()); | 
 |       encoder_config->simulcast_layers[0].num_temporal_layers = 2; | 
 |       encoder_config->content_type = VideoEncoderConfig::ContentType::kScreen; | 
 |     } | 
 |  | 
 |     void PerformTest() override { | 
 |       EXPECT_TRUE(Wait()) << "Timed out while observing incoming RTP packets."; | 
 |     } | 
 |  | 
 |     std::unique_ptr<internal::TransportAdapter> transport_adapter_; | 
 |     test::ConfigurableFrameSizeEncoder encoder_; | 
 |     test::VideoEncoderProxyFactory encoder_factory_; | 
 |  | 
 |     const size_t max_packet_size_; | 
 |     const size_t stop_size_; | 
 |     const bool test_generic_packetization_; | 
 |     const bool use_fec_; | 
 |  | 
 |     uint32_t packet_count_; | 
 |     uint32_t packets_lost_; | 
 |     uint32_t last_packet_count_; | 
 |     uint32_t last_packets_lost_; | 
 |     size_t accumulated_size_; | 
 |     size_t accumulated_payload_; | 
 |     bool fec_packet_received_; | 
 |  | 
 |     size_t current_size_rtp_; | 
 |     Mutex mutex_; | 
 |     int current_size_frame_ RTC_GUARDED_BY(mutex_); | 
 |   }; | 
 |  | 
 |   // Don't auto increment if FEC is used; continue sending frame size until | 
 |   // a FEC packet has been received. | 
 |   FrameFragmentationTest test(kMaxPacketSize, start, stop, format == kGeneric, | 
 |                               with_fec); | 
 |  | 
 |   RunBaseTest(&test); | 
 | } | 
 |  | 
 | // TODO(sprang): Is there any way of speeding up these tests? | 
 | TEST_F(VideoSendStreamTest, FragmentsGenericAccordingToMaxPacketSize) { | 
 |   TestPacketFragmentationSize(kGeneric, false); | 
 | } | 
 |  | 
 | TEST_F(VideoSendStreamTest, FragmentsGenericAccordingToMaxPacketSizeWithFec) { | 
 |   TestPacketFragmentationSize(kGeneric, true); | 
 | } | 
 |  | 
 | TEST_F(VideoSendStreamTest, FragmentsVp8AccordingToMaxPacketSize) { | 
 |   TestPacketFragmentationSize(kVP8, false); | 
 | } | 
 |  | 
 | TEST_F(VideoSendStreamTest, FragmentsVp8AccordingToMaxPacketSizeWithFec) { | 
 |   TestPacketFragmentationSize(kVP8, true); | 
 | } | 
 |  | 
 | // This test that padding stops being send after a while if the Camera stops | 
 | // producing video frames and that padding resumes if the camera restarts. | 
 | TEST_F(VideoSendStreamTest, NoPaddingWhenVideoIsMuted) { | 
 |   class NoPaddingWhenVideoIsMuted : public test::SendTest { | 
 |    public: | 
 |     NoPaddingWhenVideoIsMuted() | 
 |         : SendTest(kDefaultTimeoutMs), | 
 |           clock_(Clock::GetRealTimeClock()), | 
 |           capturer_(nullptr) {} | 
 |  | 
 |    private: | 
 |     Action OnSendRtp(const uint8_t* packet, size_t length) override { | 
 |       MutexLock lock(&mutex_); | 
 |       last_packet_time_ms_ = clock_->TimeInMilliseconds(); | 
 |  | 
 |       RtpPacket rtp_packet; | 
 |       rtp_packet.Parse(packet, length); | 
 |       const bool only_padding = rtp_packet.payload_size() == 0; | 
 |  | 
 |       if (test_state_ == kBeforeStopCapture) { | 
 |         // Packets are flowing, stop camera. | 
 |         capturer_->Stop(); | 
 |         test_state_ = kWaitingForPadding; | 
 |       } else if (test_state_ == kWaitingForPadding && only_padding) { | 
 |         // We're still getting padding, after stopping camera. | 
 |         test_state_ = kWaitingForNoPackets; | 
 |       } else if (test_state_ == kWaitingForMediaAfterCameraRestart && | 
 |                  !only_padding) { | 
 |         // Media packets are flowing again, stop camera a second time. | 
 |         capturer_->Stop(); | 
 |         test_state_ = kWaitingForPaddingAfterCameraStopsAgain; | 
 |       } else if (test_state_ == kWaitingForPaddingAfterCameraStopsAgain && | 
 |                  only_padding) { | 
 |         // Padding is still flowing, test ok. | 
 |         observation_complete_.Set(); | 
 |       } | 
 |       return SEND_PACKET; | 
 |     } | 
 |  | 
 |     Action OnSendRtcp(const uint8_t* packet, size_t length) override { | 
 |       MutexLock lock(&mutex_); | 
 |       const int kNoPacketsThresholdMs = 2000; | 
 |       if (test_state_ == kWaitingForNoPackets && | 
 |           (last_packet_time_ms_ && | 
 |            clock_->TimeInMilliseconds() - last_packet_time_ms_.value() > | 
 |                kNoPacketsThresholdMs)) { | 
 |         // No packets seen for `kNoPacketsThresholdMs`, restart camera. | 
 |         capturer_->Start(); | 
 |         test_state_ = kWaitingForMediaAfterCameraRestart; | 
 |       } | 
 |       return SEND_PACKET; | 
 |     } | 
 |  | 
 |     void ModifyVideoConfigs( | 
 |         VideoSendStream::Config* send_config, | 
 |         std::vector<VideoReceiveStream::Config>* receive_configs, | 
 |         VideoEncoderConfig* encoder_config) override { | 
 |       // Make sure padding is sent if encoder is not producing media. | 
 |       encoder_config->min_transmit_bitrate_bps = 50000; | 
 |     } | 
 |  | 
 |     void OnFrameGeneratorCapturerCreated( | 
 |         test::FrameGeneratorCapturer* frame_generator_capturer) override { | 
 |       MutexLock lock(&mutex_); | 
 |       capturer_ = frame_generator_capturer; | 
 |     } | 
 |  | 
 |     void PerformTest() override { | 
 |       EXPECT_TRUE(Wait()) | 
 |           << "Timed out while waiting for RTP packets to stop being sent."; | 
 |     } | 
 |  | 
 |     enum TestState { | 
 |       kBeforeStopCapture, | 
 |       kWaitingForPadding, | 
 |       kWaitingForNoPackets, | 
 |       kWaitingForMediaAfterCameraRestart, | 
 |       kWaitingForPaddingAfterCameraStopsAgain | 
 |     }; | 
 |  | 
 |     TestState test_state_ = kBeforeStopCapture; | 
 |     Clock* const clock_; | 
 |     Mutex mutex_; | 
 |     absl::optional<int64_t> last_packet_time_ms_ RTC_GUARDED_BY(mutex_); | 
 |     test::FrameGeneratorCapturer* capturer_ RTC_GUARDED_BY(mutex_); | 
 |   } test; | 
 |  | 
 |   RunBaseTest(&test); | 
 | } | 
 |  | 
 | TEST_F(VideoSendStreamTest, PaddingIsPrimarilyRetransmissions) { | 
 |   const int kCapacityKbps = 10000;  // 10 Mbps | 
 |   class PaddingIsPrimarilyRetransmissions : public test::EndToEndTest { | 
 |    public: | 
 |     PaddingIsPrimarilyRetransmissions() | 
 |         : EndToEndTest(kDefaultTimeoutMs), | 
 |           clock_(Clock::GetRealTimeClock()), | 
 |           padding_length_(0), | 
 |           total_length_(0), | 
 |           call_(nullptr) {} | 
 |  | 
 |    private: | 
 |     void OnCallsCreated(Call* sender_call, Call* receiver_call) override { | 
 |       call_ = sender_call; | 
 |     } | 
 |  | 
 |     Action OnSendRtp(const uint8_t* packet, size_t length) override { | 
 |       MutexLock lock(&mutex_); | 
 |  | 
 |       RtpPacket rtp_packet; | 
 |       rtp_packet.Parse(packet, length); | 
 |       padding_length_ += rtp_packet.padding_size(); | 
 |       total_length_ += length; | 
 |       return SEND_PACKET; | 
 |     } | 
 |  | 
 |     std::unique_ptr<test::PacketTransport> CreateSendTransport( | 
 |         TaskQueueBase* task_queue, | 
 |         Call* sender_call) override { | 
 |       const int kNetworkDelayMs = 50; | 
 |       BuiltInNetworkBehaviorConfig config; | 
 |       config.loss_percent = 10; | 
 |       config.link_capacity_kbps = kCapacityKbps; | 
 |       config.queue_delay_ms = kNetworkDelayMs; | 
 |       return std::make_unique<test::PacketTransport>( | 
 |           task_queue, sender_call, this, test::PacketTransport::kSender, | 
 |           payload_type_map_, | 
 |           std::make_unique<FakeNetworkPipe>( | 
 |               Clock::GetRealTimeClock(), | 
 |               std::make_unique<SimulatedNetwork>(config))); | 
 |     } | 
 |  | 
 |     void ModifyVideoConfigs( | 
 |         VideoSendStream::Config* send_config, | 
 |         std::vector<VideoReceiveStream::Config>* receive_configs, | 
 |         VideoEncoderConfig* encoder_config) override { | 
 |       // Turn on RTX. | 
 |       send_config->rtp.rtx.payload_type = kFakeVideoSendPayloadType; | 
 |       send_config->rtp.rtx.ssrcs.push_back(kSendRtxSsrcs[0]); | 
 |     } | 
 |  | 
 |     void PerformTest() override { | 
 |       // TODO(isheriff): Some platforms do not ramp up as expected to full | 
 |       // capacity due to packet scheduling delays. Fix that before getting | 
 |       // rid of this. | 
 |       SleepMs(5000); | 
 |       { | 
 |         MutexLock lock(&mutex_); | 
 |         // Expect padding to be a small percentage of total bytes sent. | 
 |         EXPECT_LT(padding_length_, .1 * total_length_); | 
 |       } | 
 |     } | 
 |  | 
 |     Mutex mutex_; | 
 |     Clock* const clock_; | 
 |     size_t padding_length_ RTC_GUARDED_BY(mutex_); | 
 |     size_t total_length_ RTC_GUARDED_BY(mutex_); | 
 |     Call* call_; | 
 |   } test; | 
 |  | 
 |   RunBaseTest(&test); | 
 | } | 
 |  | 
 | // This test first observes "high" bitrate use at which point it sends a REMB to | 
 | // indicate that it should be lowered significantly. The test then observes that | 
 | // the bitrate observed is sinking well below the min-transmit-bitrate threshold | 
 | // to verify that the min-transmit bitrate respects incoming REMB. | 
 | // | 
 | // Note that the test starts at "high" bitrate and does not ramp up to "higher" | 
 | // bitrate since no receiver block or remb is sent in the initial phase. | 
 | TEST_F(VideoSendStreamTest, MinTransmitBitrateRespectsRemb) { | 
 |   static const int kMinTransmitBitrateBps = 400000; | 
 |   static const int kHighBitrateBps = 150000; | 
 |   static const int kRembBitrateBps = 80000; | 
 |   static const int kRembRespectedBitrateBps = 100000; | 
 |   class BitrateObserver : public test::SendTest { | 
 |    public: | 
 |     explicit BitrateObserver(TaskQueueBase* task_queue) | 
 |         : SendTest(kDefaultTimeoutMs), | 
 |           task_queue_(task_queue), | 
 |           retranmission_rate_limiter_(Clock::GetRealTimeClock(), 1000), | 
 |           stream_(nullptr), | 
 |           bitrate_capped_(false), | 
 |           task_safety_flag_(PendingTaskSafetyFlag::CreateDetached()) {} | 
 |  | 
 |     ~BitrateObserver() override { | 
 |       // Make sure we free `rtp_rtcp_` in the same context as we constructed it. | 
 |       SendTask(RTC_FROM_HERE, task_queue_, [this]() { rtp_rtcp_ = nullptr; }); | 
 |     } | 
 |  | 
 |    private: | 
 |     Action OnSendRtp(const uint8_t* packet, size_t length) override { | 
 |       if (IsRtcpPacket(rtc::MakeArrayView(packet, length))) | 
 |         return DROP_PACKET; | 
 |  | 
 |       RtpPacket rtp_packet; | 
 |       RTC_CHECK(rtp_packet.Parse(packet, length)); | 
 |       const uint32_t ssrc = rtp_packet.Ssrc(); | 
 |       RTC_DCHECK(stream_); | 
 |  | 
 |       task_queue_->PostTask(ToQueuedTask(task_safety_flag_, [this, ssrc]() { | 
 |         VideoSendStream::Stats stats = stream_->GetStats(); | 
 |         if (!stats.substreams.empty()) { | 
 |           EXPECT_EQ(1u, stats.substreams.size()); | 
 |           int total_bitrate_bps = | 
 |               stats.substreams.begin()->second.total_bitrate_bps; | 
 |           test::PrintResult( | 
 |               "bitrate_stats_", "min_transmit_bitrate_low_remb", "bitrate_bps", | 
 |               static_cast<size_t>(total_bitrate_bps), "bps", false); | 
 |           if (total_bitrate_bps > kHighBitrateBps) { | 
 |             rtp_rtcp_->SetRemb(kRembBitrateBps, {ssrc}); | 
 |             bitrate_capped_ = true; | 
 |           } else if (bitrate_capped_ && | 
 |                      total_bitrate_bps < kRembRespectedBitrateBps) { | 
 |             observation_complete_.Set(); | 
 |           } | 
 |         } | 
 |       })); | 
 |  | 
 |       // Packets don't have to be delivered since the test is the receiver. | 
 |       return DROP_PACKET; | 
 |     } | 
 |  | 
 |     void OnVideoStreamsCreated( | 
 |         VideoSendStream* send_stream, | 
 |         const std::vector<VideoReceiveStream*>& receive_streams) override { | 
 |       stream_ = send_stream; | 
 |       RtpRtcpInterface::Configuration config; | 
 |       config.clock = Clock::GetRealTimeClock(); | 
 |       config.outgoing_transport = feedback_transport_.get(); | 
 |       config.retransmission_rate_limiter = &retranmission_rate_limiter_; | 
 |       rtp_rtcp_ = ModuleRtpRtcpImpl2::Create(config); | 
 |       rtp_rtcp_->SetRTCPStatus(RtcpMode::kReducedSize); | 
 |     } | 
 |  | 
 |     void ModifyVideoConfigs( | 
 |         VideoSendStream::Config* send_config, | 
 |         std::vector<VideoReceiveStream::Config>* receive_configs, | 
 |         VideoEncoderConfig* encoder_config) override { | 
 |       feedback_transport_.reset( | 
 |           new internal::TransportAdapter(send_config->send_transport)); | 
 |       feedback_transport_->Enable(); | 
 |       encoder_config->min_transmit_bitrate_bps = kMinTransmitBitrateBps; | 
 |     } | 
 |  | 
 |     void OnStreamsStopped() override { task_safety_flag_->SetNotAlive(); } | 
 |  | 
 |     void PerformTest() override { | 
 |       EXPECT_TRUE(Wait()) | 
 |           << "Timeout while waiting for low bitrate stats after REMB."; | 
 |     } | 
 |  | 
 |     TaskQueueBase* const task_queue_; | 
 |     std::unique_ptr<ModuleRtpRtcpImpl2> rtp_rtcp_; | 
 |     std::unique_ptr<internal::TransportAdapter> feedback_transport_; | 
 |     RateLimiter retranmission_rate_limiter_; | 
 |     VideoSendStream* stream_; | 
 |     bool bitrate_capped_; | 
 |     rtc::scoped_refptr<PendingTaskSafetyFlag> task_safety_flag_; | 
 |   } test(task_queue()); | 
 |  | 
 |   RunBaseTest(&test); | 
 | } | 
 |  | 
 | TEST_F(VideoSendStreamTest, ChangingNetworkRoute) { | 
 |   static const int kStartBitrateBps = 300000; | 
 |   static const int kNewMaxBitrateBps = 1234567; | 
 |   static const uint8_t kExtensionId = kTransportSequenceNumberExtensionId; | 
 |   class ChangingNetworkRouteTest : public test::EndToEndTest { | 
 |    public: | 
 |     explicit ChangingNetworkRouteTest(TaskQueueBase* task_queue) | 
 |         : EndToEndTest(test::CallTest::kDefaultTimeoutMs), | 
 |           task_queue_(task_queue), | 
 |           call_(nullptr) { | 
 |       module_process_thread_.Detach(); | 
 |       task_queue_thread_.Detach(); | 
 |       extensions_.Register<TransportSequenceNumber>(kExtensionId); | 
 |     } | 
 |  | 
 |     ~ChangingNetworkRouteTest() { | 
 |       // Block until all already posted tasks run to avoid 'use after free' | 
 |       // when such task accesses `this`. | 
 |       SendTask(RTC_FROM_HERE, task_queue_, [] {}); | 
 |     } | 
 |  | 
 |     void OnCallsCreated(Call* sender_call, Call* receiver_call) override { | 
 |       RTC_DCHECK_RUN_ON(&task_queue_thread_); | 
 |       RTC_DCHECK(!call_); | 
 |       call_ = sender_call; | 
 |     } | 
 |  | 
 |     void ModifyVideoConfigs( | 
 |         VideoSendStream::Config* send_config, | 
 |         std::vector<VideoReceiveStream::Config>* receive_configs, | 
 |         VideoEncoderConfig* encoder_config) override { | 
 |       RTC_DCHECK_RUN_ON(&task_queue_thread_); | 
 |       send_config->rtp.extensions.clear(); | 
 |       send_config->rtp.extensions.push_back(RtpExtension( | 
 |           RtpExtension::kTransportSequenceNumberUri, kExtensionId)); | 
 |       (*receive_configs)[0].rtp.extensions = send_config->rtp.extensions; | 
 |       (*receive_configs)[0].rtp.transport_cc = true; | 
 |     } | 
 |  | 
 |     void ModifyAudioConfigs( | 
 |         AudioSendStream::Config* send_config, | 
 |         std::vector<AudioReceiveStream::Config>* receive_configs) override { | 
 |       RTC_DCHECK_RUN_ON(&task_queue_thread_); | 
 |       send_config->rtp.extensions.clear(); | 
 |       send_config->rtp.extensions.push_back(RtpExtension( | 
 |           RtpExtension::kTransportSequenceNumberUri, kExtensionId)); | 
 |       (*receive_configs)[0].rtp.extensions.clear(); | 
 |       (*receive_configs)[0].rtp.extensions = send_config->rtp.extensions; | 
 |       (*receive_configs)[0].rtp.transport_cc = true; | 
 |     } | 
 |  | 
 |     Action OnSendRtp(const uint8_t* packet, size_t length) override { | 
 |       RTC_DCHECK_RUN_ON(&module_process_thread_); | 
 |       task_queue_->PostTask(ToQueuedTask([this]() { | 
 |         RTC_DCHECK_RUN_ON(&task_queue_thread_); | 
 |         if (!call_) | 
 |           return; | 
 |         Call::Stats stats = call_->GetStats(); | 
 |         if (stats.send_bandwidth_bps > kStartBitrateBps) | 
 |           observation_complete_.Set(); | 
 |       })); | 
 |       return SEND_PACKET; | 
 |     } | 
 |  | 
 |     void OnStreamsStopped() override { | 
 |       RTC_DCHECK_RUN_ON(&task_queue_thread_); | 
 |       call_ = nullptr; | 
 |     } | 
 |  | 
 |     void PerformTest() override { | 
 |       rtc::NetworkRoute new_route; | 
 |       new_route.connected = true; | 
 |       new_route.local = rtc::RouteEndpoint::CreateWithNetworkId(10); | 
 |       new_route.remote = rtc::RouteEndpoint::CreateWithNetworkId(20); | 
 |       BitrateConstraints bitrate_config; | 
 |  | 
 |       SendTask(RTC_FROM_HERE, task_queue_, | 
 |                [this, &new_route, &bitrate_config]() { | 
 |                  RTC_DCHECK_RUN_ON(&task_queue_thread_); | 
 |                  call_->GetTransportControllerSend()->OnNetworkRouteChanged( | 
 |                      "transport", new_route); | 
 |                  bitrate_config.start_bitrate_bps = kStartBitrateBps; | 
 |                  call_->GetTransportControllerSend()->SetSdpBitrateParameters( | 
 |                      bitrate_config); | 
 |                }); | 
 |  | 
 |       EXPECT_TRUE(Wait()) | 
 |           << "Timed out while waiting for start bitrate to be exceeded."; | 
 |  | 
 |       SendTask( | 
 |           RTC_FROM_HERE, task_queue_, [this, &new_route, &bitrate_config]() { | 
 |             RTC_DCHECK_RUN_ON(&task_queue_thread_); | 
 |             bitrate_config.start_bitrate_bps = -1; | 
 |             bitrate_config.max_bitrate_bps = kNewMaxBitrateBps; | 
 |             call_->GetTransportControllerSend()->SetSdpBitrateParameters( | 
 |                 bitrate_config); | 
 |             // TODO(holmer): We should set the last sent packet id here and | 
 |             // verify that we correctly ignore any packet loss reported prior to | 
 |             // that id. | 
 |             new_route.local = rtc::RouteEndpoint::CreateWithNetworkId( | 
 |                 new_route.local.network_id() + 1); | 
 |             call_->GetTransportControllerSend()->OnNetworkRouteChanged( | 
 |                 "transport", new_route); | 
 |             EXPECT_GE(call_->GetStats().send_bandwidth_bps, kStartBitrateBps); | 
 |           }); | 
 |     } | 
 |  | 
 |    private: | 
 |     webrtc::SequenceChecker module_process_thread_; | 
 |     webrtc::SequenceChecker task_queue_thread_; | 
 |     TaskQueueBase* const task_queue_; | 
 |     RtpHeaderExtensionMap extensions_; | 
 |     Call* call_ RTC_GUARDED_BY(task_queue_thread_); | 
 |   } test(task_queue()); | 
 |  | 
 |   RunBaseTest(&test); | 
 | } | 
 |  | 
 | // Test that if specified, relay cap is lifted on transition to direct | 
 | // connection. | 
 | // TODO(https://bugs.webrtc.org/13353): Test disabled  due to flakiness. | 
 | TEST_F(VideoSendStreamTest, DISABLED_RelayToDirectRoute) { | 
 |   static const int kStartBitrateBps = 300000; | 
 |   static const int kRelayBandwidthCapBps = 800000; | 
 |   static const int kMinPacketsToSend = 100; | 
 |   webrtc::test::ScopedKeyValueConfig field_trials( | 
 |       field_trials_, "WebRTC-Bwe-NetworkRouteConstraints/relay_cap:" + | 
 |                          std::to_string(kRelayBandwidthCapBps) + "bps/"); | 
 |  | 
 |   class RelayToDirectRouteTest : public test::EndToEndTest { | 
 |    public: | 
 |     explicit RelayToDirectRouteTest(TaskQueueBase* task_queue) | 
 |         : EndToEndTest(test::CallTest::kDefaultTimeoutMs), | 
 |           task_queue_(task_queue), | 
 |           call_(nullptr), | 
 |           packets_sent_(0), | 
 |           relayed_phase_(true) { | 
 |       module_process_thread_.Detach(); | 
 |       task_queue_thread_.Detach(); | 
 |     } | 
 |  | 
 |     ~RelayToDirectRouteTest() { | 
 |       // Block until all already posted tasks run to avoid 'use after free' | 
 |       // when such task accesses `this`. | 
 |       SendTask(RTC_FROM_HERE, task_queue_, [] {}); | 
 |     } | 
 |  | 
 |     void OnCallsCreated(Call* sender_call, Call* receiver_call) override { | 
 |       RTC_DCHECK_RUN_ON(&task_queue_thread_); | 
 |       RTC_DCHECK(!call_); | 
 |       call_ = sender_call; | 
 |     } | 
 |  | 
 |     Action OnSendRtp(const uint8_t* packet, size_t length) override { | 
 |       RTC_DCHECK_RUN_ON(&module_process_thread_); | 
 |       task_queue_->PostTask(ToQueuedTask([this]() { | 
 |         RTC_DCHECK_RUN_ON(&task_queue_thread_); | 
 |         if (!call_) | 
 |           return; | 
 |         bool had_time_to_exceed_cap_in_relayed_phase = | 
 |             relayed_phase_ && ++packets_sent_ > kMinPacketsToSend; | 
 |         bool did_exceed_cap = | 
 |             call_->GetStats().send_bandwidth_bps > kRelayBandwidthCapBps; | 
 |         if (did_exceed_cap || had_time_to_exceed_cap_in_relayed_phase) | 
 |           observation_complete_.Set(); | 
 |       })); | 
 |       return SEND_PACKET; | 
 |     } | 
 |  | 
 |     void OnStreamsStopped() override { | 
 |       RTC_DCHECK_RUN_ON(&task_queue_thread_); | 
 |       call_ = nullptr; | 
 |     } | 
 |  | 
 |     void PerformTest() override { | 
 |       rtc::NetworkRoute route; | 
 |       route.connected = true; | 
 |       route.local = rtc::RouteEndpoint::CreateWithNetworkId(10); | 
 |       route.remote = rtc::RouteEndpoint::CreateWithNetworkId(20); | 
 |  | 
 |       SendTask(RTC_FROM_HERE, task_queue_, [this, &route]() { | 
 |         RTC_DCHECK_RUN_ON(&task_queue_thread_); | 
 |         relayed_phase_ = true; | 
 |         route.remote = route.remote.CreateWithTurn(true); | 
 |         call_->GetTransportControllerSend()->OnNetworkRouteChanged("transport", | 
 |                                                                    route); | 
 |         BitrateConstraints bitrate_config; | 
 |         bitrate_config.start_bitrate_bps = kStartBitrateBps; | 
 |  | 
 |         call_->GetTransportControllerSend()->SetSdpBitrateParameters( | 
 |             bitrate_config); | 
 |       }); | 
 |  | 
 |       EXPECT_TRUE(Wait()) | 
 |           << "Timeout waiting for sufficient packets sent count."; | 
 |  | 
 |       SendTask(RTC_FROM_HERE, task_queue_, [this, &route]() { | 
 |         RTC_DCHECK_RUN_ON(&task_queue_thread_); | 
 |         EXPECT_LE(call_->GetStats().send_bandwidth_bps, kRelayBandwidthCapBps); | 
 |  | 
 |         route.remote = route.remote.CreateWithTurn(false); | 
 |         call_->GetTransportControllerSend()->OnNetworkRouteChanged("transport", | 
 |                                                                    route); | 
 |         relayed_phase_ = false; | 
 |         observation_complete_.Reset(); | 
 |       }); | 
 |  | 
 |       EXPECT_TRUE(Wait()) | 
 |           << "Timeout while waiting for bandwidth to outgrow relay cap."; | 
 |     } | 
 |  | 
 |    private: | 
 |     webrtc::SequenceChecker module_process_thread_; | 
 |     webrtc::SequenceChecker task_queue_thread_; | 
 |     TaskQueueBase* const task_queue_; | 
 |     Call* call_ RTC_GUARDED_BY(task_queue_thread_); | 
 |     int packets_sent_ RTC_GUARDED_BY(task_queue_thread_); | 
 |     bool relayed_phase_ RTC_GUARDED_BY(task_queue_thread_); | 
 |   } test(task_queue()); | 
 |  | 
 |   RunBaseTest(&test); | 
 | } | 
 |  | 
 | TEST_F(VideoSendStreamTest, ChangingTransportOverhead) { | 
 |   class ChangingTransportOverheadTest : public test::EndToEndTest { | 
 |    public: | 
 |     explicit ChangingTransportOverheadTest(TaskQueueBase* task_queue) | 
 |         : EndToEndTest(test::CallTest::kDefaultTimeoutMs), | 
 |           task_queue_(task_queue), | 
 |           call_(nullptr), | 
 |           packets_sent_(0), | 
 |           transport_overhead_(0) {} | 
 |  | 
 |     void OnCallsCreated(Call* sender_call, Call* receiver_call) override { | 
 |       call_ = sender_call; | 
 |     } | 
 |  | 
 |     Action OnSendRtp(const uint8_t* packet, size_t length) override { | 
 |       EXPECT_LE(length, kMaxRtpPacketSize); | 
 |       MutexLock lock(&lock_); | 
 |       if (++packets_sent_ < 100) | 
 |         return SEND_PACKET; | 
 |       observation_complete_.Set(); | 
 |       return SEND_PACKET; | 
 |     } | 
 |  | 
 |     void ModifyVideoConfigs( | 
 |         VideoSendStream::Config* send_config, | 
 |         std::vector<VideoReceiveStream::Config>* receive_configs, | 
 |         VideoEncoderConfig* encoder_config) override { | 
 |       send_config->rtp.max_packet_size = kMaxRtpPacketSize; | 
 |     } | 
 |  | 
 |     void PerformTest() override { | 
 |       SendTask(RTC_FROM_HERE, task_queue_, [this]() { | 
 |         transport_overhead_ = 100; | 
 |         call_->GetTransportControllerSend()->OnTransportOverheadChanged( | 
 |             transport_overhead_); | 
 |       }); | 
 |  | 
 |       EXPECT_TRUE(Wait()); | 
 |  | 
 |       { | 
 |         MutexLock lock(&lock_); | 
 |         packets_sent_ = 0; | 
 |       } | 
 |  | 
 |       SendTask(RTC_FROM_HERE, task_queue_, [this]() { | 
 |         transport_overhead_ = 500; | 
 |         call_->GetTransportControllerSend()->OnTransportOverheadChanged( | 
 |             transport_overhead_); | 
 |       }); | 
 |  | 
 |       EXPECT_TRUE(Wait()); | 
 |     } | 
 |  | 
 |    private: | 
 |     TaskQueueBase* const task_queue_; | 
 |     Call* call_; | 
 |     Mutex lock_; | 
 |     int packets_sent_ RTC_GUARDED_BY(lock_); | 
 |     int transport_overhead_; | 
 |     const size_t kMaxRtpPacketSize = 1000; | 
 |   } test(task_queue()); | 
 |  | 
 |   RunBaseTest(&test); | 
 | } | 
 |  | 
 | // Test class takes takes as argument a switch selecting if type switch should | 
 | // occur and a function pointer to reset the send stream. This is necessary | 
 | // since you cannot change the content type of a VideoSendStream, you need to | 
 | // recreate it. Stopping and recreating the stream can only be done on the main | 
 | // thread and in the context of VideoSendStreamTest (not BaseTest). | 
 | template <typename T> | 
 | class MaxPaddingSetTest : public test::SendTest { | 
 |  public: | 
 |   static const uint32_t kMinTransmitBitrateBps = 400000; | 
 |   static const uint32_t kActualEncodeBitrateBps = 40000; | 
 |   static const uint32_t kMinPacketsToSend = 50; | 
 |  | 
 |   MaxPaddingSetTest(bool test_switch_content_type, | 
 |                     T* stream_reset_fun, | 
 |                     TaskQueueBase* task_queue) | 
 |       : SendTest(test::CallTest::kDefaultTimeoutMs), | 
 |         running_without_padding_(test_switch_content_type), | 
 |         stream_resetter_(stream_reset_fun), | 
 |         task_queue_(task_queue) { | 
 |     RTC_DCHECK(stream_resetter_); | 
 |     module_process_thread_.Detach(); | 
 |     task_queue_thread_.Detach(); | 
 |   } | 
 |  | 
 |   ~MaxPaddingSetTest() { | 
 |     // Block until all already posted tasks run to avoid 'use after free' | 
 |     // when such task accesses `this`. | 
 |     SendTask(RTC_FROM_HERE, task_queue_, [] {}); | 
 |   } | 
 |  | 
 |   void ModifyVideoConfigs( | 
 |       VideoSendStream::Config* send_config, | 
 |       std::vector<VideoReceiveStream::Config>* receive_configs, | 
 |       VideoEncoderConfig* encoder_config) override { | 
 |     RTC_DCHECK_RUN_ON(&task_queue_thread_); | 
 |     RTC_DCHECK_EQ(1, encoder_config->number_of_streams); | 
 |     if (running_without_padding_) { | 
 |       encoder_config->min_transmit_bitrate_bps = 0; | 
 |       encoder_config->content_type = | 
 |           VideoEncoderConfig::ContentType::kRealtimeVideo; | 
 |     } else { | 
 |       encoder_config->min_transmit_bitrate_bps = kMinTransmitBitrateBps; | 
 |       encoder_config->content_type = VideoEncoderConfig::ContentType::kScreen; | 
 |     } | 
 |     send_stream_config_ = send_config->Copy(); | 
 |     encoder_config_ = encoder_config->Copy(); | 
 |   } | 
 |  | 
 |   void OnCallsCreated(Call* sender_call, Call* receiver_call) override { | 
 |     RTC_DCHECK_RUN_ON(&task_queue_thread_); | 
 |     RTC_DCHECK(task_queue_->IsCurrent()); | 
 |     RTC_DCHECK(!call_); | 
 |     RTC_DCHECK(sender_call); | 
 |     call_ = sender_call; | 
 |   } | 
 |  | 
 |   // Called on the pacer thread. | 
 |   Action OnSendRtp(const uint8_t* packet, size_t length) override { | 
 |     RTC_DCHECK_RUN_ON(&module_process_thread_); | 
 |  | 
 |     // Check the stats on the correct thread and signal the 'complete' flag | 
 |     // once we detect that we're done. | 
 |  | 
 |     task_queue_->PostTask(ToQueuedTask([this]() { | 
 |       RTC_DCHECK_RUN_ON(&task_queue_thread_); | 
 |       // In case we get a callback during teardown. | 
 |       // When this happens, OnStreamsStopped() has been called already, | 
 |       // `call_` is null and the streams are being torn down. | 
 |       if (!call_) | 
 |         return; | 
 |  | 
 |       ++packets_sent_; | 
 |  | 
 |       Call::Stats stats = call_->GetStats(); | 
 |       if (running_without_padding_) { | 
 |         EXPECT_EQ(0, stats.max_padding_bitrate_bps); | 
 |  | 
 |         // Wait until at least kMinPacketsToSend frames have been encoded, so | 
 |         // that we have reliable data. | 
 |         if (packets_sent_ < kMinPacketsToSend) | 
 |           return; | 
 |  | 
 |         // We've sent kMinPacketsToSend packets with default configuration, | 
 |         // switch to enabling screen content and setting min transmit bitrate. | 
 |         // Note that we need to recreate the stream if changing content type. | 
 |         packets_sent_ = 0; | 
 |  | 
 |         encoder_config_.min_transmit_bitrate_bps = kMinTransmitBitrateBps; | 
 |         encoder_config_.content_type = VideoEncoderConfig::ContentType::kScreen; | 
 |  | 
 |         running_without_padding_ = false; | 
 |         (*stream_resetter_)(send_stream_config_, encoder_config_); | 
 |       } else { | 
 |         // Make sure the pacer has been configured with a min transmit bitrate. | 
 |         if (stats.max_padding_bitrate_bps > 0) { | 
 |           observation_complete_.Set(); | 
 |         } | 
 |       } | 
 |     })); | 
 |  | 
 |     return SEND_PACKET; | 
 |   } | 
 |  | 
 |   // Called on `task_queue_` | 
 |   void OnStreamsStopped() override { | 
 |     RTC_DCHECK_RUN_ON(&task_queue_thread_); | 
 |     RTC_DCHECK(task_queue_->IsCurrent()); | 
 |     call_ = nullptr; | 
 |   } | 
 |  | 
 |   void PerformTest() override { | 
 |     ASSERT_TRUE(Wait()) << "Timed out waiting for a valid padding bitrate."; | 
 |   } | 
 |  | 
 |  private: | 
 |   webrtc::SequenceChecker task_queue_thread_; | 
 |   Call* call_ RTC_GUARDED_BY(task_queue_thread_) = nullptr; | 
 |   VideoSendStream::Config send_stream_config_{nullptr}; | 
 |   VideoEncoderConfig encoder_config_; | 
 |   webrtc::SequenceChecker module_process_thread_; | 
 |   uint32_t packets_sent_ RTC_GUARDED_BY(task_queue_thread_) = 0; | 
 |   bool running_without_padding_ RTC_GUARDED_BY(task_queue_thread_); | 
 |   T* const stream_resetter_; | 
 |   TaskQueueBase* const task_queue_; | 
 | }; | 
 |  | 
 | TEST_F(VideoSendStreamTest, RespectsMinTransmitBitrate) { | 
 |   auto reset_fun = [](const VideoSendStream::Config& send_stream_config, | 
 |                       const VideoEncoderConfig& encoder_config) {}; | 
 |   MaxPaddingSetTest<decltype(reset_fun)> test(false, &reset_fun, task_queue()); | 
 |   RunBaseTest(&test); | 
 | } | 
 |  | 
 | TEST_F(VideoSendStreamTest, RespectsMinTransmitBitrateAfterContentSwitch) { | 
 |   // Function for removing and recreating the send stream with a new config. | 
 |   auto reset_fun = [this](const VideoSendStream::Config& send_stream_config, | 
 |                           const VideoEncoderConfig& encoder_config) { | 
 |     RTC_DCHECK(task_queue()->IsCurrent()); | 
 |     Stop(); | 
 |     DestroyVideoSendStreams(); | 
 |     SetVideoSendConfig(send_stream_config); | 
 |     SetVideoEncoderConfig(encoder_config); | 
 |     CreateVideoSendStreams(); | 
 |     SetVideoDegradation(DegradationPreference::MAINTAIN_RESOLUTION); | 
 |     Start(); | 
 |   }; | 
 |   MaxPaddingSetTest<decltype(reset_fun)> test(true, &reset_fun, task_queue()); | 
 |   RunBaseTest(&test); | 
 | } | 
 |  | 
 | // This test verifies that new frame sizes reconfigures encoders even though not | 
 | // (yet) sending. The purpose of this is to permit encoding as quickly as | 
 | // possible once we start sending. Likely the frames being input are from the | 
 | // same source that will be sent later, which just means that we're ready | 
 | // earlier. | 
 | TEST_F(VideoSendStreamTest, | 
 |        EncoderReconfigureOnResolutionChangeWhenNotSending) { | 
 |   class EncoderObserver : public test::FakeEncoder { | 
 |    public: | 
 |     EncoderObserver() | 
 |         : FakeEncoder(Clock::GetRealTimeClock()), | 
 |           last_initialized_frame_width_(0), | 
 |           last_initialized_frame_height_(0) {} | 
 |  | 
 |     void WaitForResolution(int width, int height) { | 
 |       { | 
 |         MutexLock lock(&mutex_); | 
 |         if (last_initialized_frame_width_ == width && | 
 |             last_initialized_frame_height_ == height) { | 
 |           return; | 
 |         } | 
 |       } | 
 |       EXPECT_TRUE( | 
 |           init_encode_called_.Wait(VideoSendStreamTest::kDefaultTimeoutMs)); | 
 |       { | 
 |         MutexLock lock(&mutex_); | 
 |         EXPECT_EQ(width, last_initialized_frame_width_); | 
 |         EXPECT_EQ(height, last_initialized_frame_height_); | 
 |       } | 
 |     } | 
 |  | 
 |    private: | 
 |     int32_t InitEncode(const VideoCodec* config, | 
 |                        const Settings& settings) override { | 
 |       MutexLock lock(&mutex_); | 
 |       last_initialized_frame_width_ = config->width; | 
 |       last_initialized_frame_height_ = config->height; | 
 |       init_encode_called_.Set(); | 
 |       return FakeEncoder::InitEncode(config, settings); | 
 |     } | 
 |  | 
 |     int32_t Encode(const VideoFrame& input_image, | 
 |                    const std::vector<VideoFrameType>* frame_types) override { | 
 |       ADD_FAILURE() | 
 |           << "Unexpected Encode call since the send stream is not started"; | 
 |       return 0; | 
 |     } | 
 |  | 
 |     Mutex mutex_; | 
 |     rtc::Event init_encode_called_; | 
 |     int last_initialized_frame_width_ RTC_GUARDED_BY(&mutex_); | 
 |     int last_initialized_frame_height_ RTC_GUARDED_BY(&mutex_); | 
 |   }; | 
 |  | 
 |   test::NullTransport transport; | 
 |   EncoderObserver encoder; | 
 |   test::VideoEncoderProxyFactory encoder_factory(&encoder); | 
 |  | 
 |   SendTask(RTC_FROM_HERE, task_queue(), [this, &transport, &encoder_factory]() { | 
 |     CreateSenderCall(); | 
 |     CreateSendConfig(1, 0, 0, &transport); | 
 |     GetVideoSendConfig()->encoder_settings.encoder_factory = &encoder_factory; | 
 |     CreateVideoStreams(); | 
 |     CreateFrameGeneratorCapturer(kDefaultFramerate, kDefaultWidth, | 
 |                                  kDefaultHeight); | 
 |     frame_generator_capturer_->Start(); | 
 |   }); | 
 |  | 
 |   encoder.WaitForResolution(kDefaultWidth, kDefaultHeight); | 
 |  | 
 |   SendTask(RTC_FROM_HERE, task_queue(), [this]() { | 
 |     frame_generator_capturer_->ChangeResolution(kDefaultWidth * 2, | 
 |                                                 kDefaultHeight * 2); | 
 |   }); | 
 |  | 
 |   encoder.WaitForResolution(kDefaultWidth * 2, kDefaultHeight * 2); | 
 |  | 
 |   SendTask(RTC_FROM_HERE, task_queue(), [this]() { | 
 |     DestroyStreams(); | 
 |     DestroyCalls(); | 
 |   }); | 
 | } | 
 |  | 
 | TEST_F(VideoSendStreamTest, CanReconfigureToUseStartBitrateAbovePreviousMax) { | 
 |   class StartBitrateObserver : public test::FakeEncoder { | 
 |    public: | 
 |     StartBitrateObserver() | 
 |         : FakeEncoder(Clock::GetRealTimeClock()), start_bitrate_kbps_(0) {} | 
 |     int32_t InitEncode(const VideoCodec* config, | 
 |                        const Settings& settings) override { | 
 |       MutexLock lock(&mutex_); | 
 |       start_bitrate_kbps_ = config->startBitrate; | 
 |       start_bitrate_changed_.Set(); | 
 |       return FakeEncoder::InitEncode(config, settings); | 
 |     } | 
 |  | 
 |     void SetRates(const RateControlParameters& parameters) override { | 
 |       MutexLock lock(&mutex_); | 
 |       start_bitrate_kbps_ = parameters.bitrate.get_sum_kbps(); | 
 |       start_bitrate_changed_.Set(); | 
 |       FakeEncoder::SetRates(parameters); | 
 |     } | 
 |  | 
 |     int GetStartBitrateKbps() const { | 
 |       MutexLock lock(&mutex_); | 
 |       return start_bitrate_kbps_; | 
 |     } | 
 |  | 
 |     bool WaitForStartBitrate() { | 
 |       return start_bitrate_changed_.Wait( | 
 |           VideoSendStreamTest::kDefaultTimeoutMs); | 
 |     } | 
 |  | 
 |    private: | 
 |     mutable Mutex mutex_; | 
 |     rtc::Event start_bitrate_changed_; | 
 |     int start_bitrate_kbps_ RTC_GUARDED_BY(mutex_); | 
 |   }; | 
 |  | 
 |   CreateSenderCall(); | 
 |  | 
 |   test::NullTransport transport; | 
 |   CreateSendConfig(1, 0, 0, &transport); | 
 |  | 
 |   BitrateConstraints bitrate_config; | 
 |   bitrate_config.start_bitrate_bps = | 
 |       2 * GetVideoEncoderConfig()->max_bitrate_bps; | 
 |   sender_call_->GetTransportControllerSend()->SetSdpBitrateParameters( | 
 |       bitrate_config); | 
 |  | 
 |   StartBitrateObserver encoder; | 
 |   test::VideoEncoderProxyFactory encoder_factory(&encoder); | 
 |   GetVideoSendConfig()->encoder_settings.encoder_factory = &encoder_factory; | 
 |  | 
 |   CreateVideoStreams(); | 
 |  | 
 |   // Start capturing and encoding frames to force encoder reconfiguration. | 
 |   CreateFrameGeneratorCapturer(kDefaultFramerate, kDefaultWidth, | 
 |                                kDefaultHeight); | 
 |   frame_generator_capturer_->Start(); | 
 |   // TODO(crbug/1255737): Added manual current thread message processing because | 
 |   // the test code context is interpreted as the worker thread and we assume | 
 |   // progress on it. The test should probably be ported to use simulated time | 
 |   // instead (ported to a scenario test perhaps?). | 
 |   rtc::Thread::Current()->ProcessMessages(5000); | 
 |  | 
 |   EXPECT_TRUE(encoder.WaitForStartBitrate()); | 
 |   EXPECT_EQ(GetVideoEncoderConfig()->max_bitrate_bps / 1000, | 
 |             encoder.GetStartBitrateKbps()); | 
 |  | 
 |   GetVideoEncoderConfig()->max_bitrate_bps = | 
 |       2 * bitrate_config.start_bitrate_bps; | 
 |   GetVideoSendStream()->ReconfigureVideoEncoder( | 
 |       GetVideoEncoderConfig()->Copy()); | 
 |   // TODO(crbug/1255737): Added manual current thread message processing because | 
 |   // the test code context is interpreted as the worker thread and we assume | 
 |   // progress on it. The test should probably be ported to use simulated time | 
 |   // instead (ported to a scenario test perhaps?). | 
 |   rtc::Thread::Current()->ProcessMessages(5000); | 
 |  | 
 |   // New bitrate should be reconfigured above the previous max. As there's no | 
 |   // network connection this shouldn't be flaky, as no bitrate should've been | 
 |   // reported in between. | 
 |   EXPECT_TRUE(encoder.WaitForStartBitrate()); | 
 |   EXPECT_EQ(bitrate_config.start_bitrate_bps / 1000, | 
 |             encoder.GetStartBitrateKbps()); | 
 |  | 
 |   DestroyStreams(); | 
 | } | 
 |  | 
 | class StartStopBitrateObserver : public test::FakeEncoder { | 
 |  public: | 
 |   StartStopBitrateObserver() : FakeEncoder(Clock::GetRealTimeClock()) {} | 
 |   int32_t InitEncode(const VideoCodec* config, | 
 |                      const Settings& settings) override { | 
 |     MutexLock lock(&mutex_); | 
 |     encoder_init_.Set(); | 
 |     return FakeEncoder::InitEncode(config, settings); | 
 |   } | 
 |  | 
 |   void SetRates(const RateControlParameters& parameters) override { | 
 |     MutexLock lock(&mutex_); | 
 |     bitrate_kbps_ = parameters.bitrate.get_sum_kbps(); | 
 |     bitrate_changed_.Set(); | 
 |     FakeEncoder::SetRates(parameters); | 
 |   } | 
 |  | 
 |   bool WaitForEncoderInit() { | 
 |     return encoder_init_.Wait(VideoSendStreamTest::kDefaultTimeoutMs); | 
 |   } | 
 |  | 
 |   bool WaitBitrateChanged(WaitUntil until) { | 
 |     do { | 
 |       absl::optional<int> bitrate_kbps; | 
 |       { | 
 |         MutexLock lock(&mutex_); | 
 |         bitrate_kbps = bitrate_kbps_; | 
 |       } | 
 |       if (!bitrate_kbps) | 
 |         continue; | 
 |  | 
 |       if ((until == WaitUntil::kNonZero && *bitrate_kbps > 0) || | 
 |           (until == WaitUntil::kZero && *bitrate_kbps == 0)) { | 
 |         return true; | 
 |       } | 
 |     } while (bitrate_changed_.Wait(VideoSendStreamTest::kDefaultTimeoutMs)); | 
 |     return false; | 
 |   } | 
 |  | 
 |  private: | 
 |   Mutex mutex_; | 
 |   rtc::Event encoder_init_; | 
 |   rtc::Event bitrate_changed_; | 
 |   absl::optional<int> bitrate_kbps_ RTC_GUARDED_BY(mutex_); | 
 | }; | 
 |  | 
 | TEST_F(VideoSendStreamTest, EncoderIsProperlyInitializedAndDestroyed) { | 
 |   class EncoderStateObserver : public test::SendTest, public VideoEncoder { | 
 |    public: | 
 |     explicit EncoderStateObserver(TaskQueueBase* task_queue) | 
 |         : SendTest(kDefaultTimeoutMs), | 
 |           task_queue_(task_queue), | 
 |           stream_(nullptr), | 
 |           initialized_(false), | 
 |           callback_registered_(false), | 
 |           num_releases_(0), | 
 |           released_(false), | 
 |           encoder_factory_(this) {} | 
 |  | 
 |     bool IsReleased() RTC_LOCKS_EXCLUDED(mutex_) { | 
 |       MutexLock lock(&mutex_); | 
 |       return released_; | 
 |     } | 
 |  | 
 |     bool IsReadyForEncode() RTC_LOCKS_EXCLUDED(mutex_) { | 
 |       MutexLock lock(&mutex_); | 
 |       return IsReadyForEncodeLocked(); | 
 |     } | 
 |  | 
 |     size_t num_releases() RTC_LOCKS_EXCLUDED(mutex_) { | 
 |       MutexLock lock(&mutex_); | 
 |       return num_releases_; | 
 |     } | 
 |  | 
 |    private: | 
 |     bool IsReadyForEncodeLocked() RTC_EXCLUSIVE_LOCKS_REQUIRED(mutex_) { | 
 |       return initialized_ && callback_registered_; | 
 |     } | 
 |  | 
 |     void SetFecControllerOverride( | 
 |         FecControllerOverride* fec_controller_override) override { | 
 |       // Ignored. | 
 |     } | 
 |  | 
 |     int32_t InitEncode(const VideoCodec* codecSettings, | 
 |                        const Settings& settings) override | 
 |         RTC_LOCKS_EXCLUDED(mutex_) { | 
 |       MutexLock lock(&mutex_); | 
 |       EXPECT_FALSE(initialized_); | 
 |       initialized_ = true; | 
 |       released_ = false; | 
 |       return 0; | 
 |     } | 
 |  | 
 |     int32_t Encode(const VideoFrame& inputImage, | 
 |                    const std::vector<VideoFrameType>* frame_types) override { | 
 |       EXPECT_TRUE(IsReadyForEncode()); | 
 |  | 
 |       observation_complete_.Set(); | 
 |       return 0; | 
 |     } | 
 |  | 
 |     int32_t RegisterEncodeCompleteCallback( | 
 |         EncodedImageCallback* callback) override RTC_LOCKS_EXCLUDED(mutex_) { | 
 |       MutexLock lock(&mutex_); | 
 |       EXPECT_TRUE(initialized_); | 
 |       callback_registered_ = true; | 
 |       return 0; | 
 |     } | 
 |  | 
 |     int32_t Release() override RTC_LOCKS_EXCLUDED(mutex_) { | 
 |       MutexLock lock(&mutex_); | 
 |       EXPECT_TRUE(IsReadyForEncodeLocked()); | 
 |       EXPECT_FALSE(released_); | 
 |       initialized_ = false; | 
 |       callback_registered_ = false; | 
 |       released_ = true; | 
 |       ++num_releases_; | 
 |       return 0; | 
 |     } | 
 |  | 
 |     void SetRates(const RateControlParameters& parameters) override { | 
 |       EXPECT_TRUE(IsReadyForEncode()); | 
 |     } | 
 |  | 
 |     void OnVideoStreamsCreated( | 
 |         VideoSendStream* send_stream, | 
 |         const std::vector<VideoReceiveStream*>& receive_streams) override { | 
 |       stream_ = send_stream; | 
 |     } | 
 |  | 
 |     void ModifyVideoConfigs( | 
 |         VideoSendStream::Config* send_config, | 
 |         std::vector<VideoReceiveStream::Config>* receive_configs, | 
 |         VideoEncoderConfig* encoder_config) override { | 
 |       send_config->encoder_settings.encoder_factory = &encoder_factory_; | 
 |       encoder_config_ = encoder_config->Copy(); | 
 |     } | 
 |  | 
 |     void PerformTest() override { | 
 |       EXPECT_TRUE(Wait()) << "Timed out while waiting for Encode."; | 
 |  | 
 |       SendTask(RTC_FROM_HERE, task_queue_, [this]() { | 
 |         EXPECT_EQ(0u, num_releases()); | 
 |         stream_->ReconfigureVideoEncoder(std::move(encoder_config_)); | 
 |         EXPECT_EQ(0u, num_releases()); | 
 |         stream_->Stop(); | 
 |         // Encoder should not be released before destroying the VideoSendStream. | 
 |         EXPECT_FALSE(IsReleased()); | 
 |         EXPECT_TRUE(IsReadyForEncode()); | 
 |         stream_->Start(); | 
 |       }); | 
 |  | 
 |       // Sanity check, make sure we still encode frames with this encoder. | 
 |       EXPECT_TRUE(Wait()) << "Timed out while waiting for Encode."; | 
 |     } | 
 |  | 
 |     TaskQueueBase* const task_queue_; | 
 |     Mutex mutex_; | 
 |     VideoSendStream* stream_; | 
 |     bool initialized_ RTC_GUARDED_BY(mutex_); | 
 |     bool callback_registered_ RTC_GUARDED_BY(mutex_); | 
 |     size_t num_releases_ RTC_GUARDED_BY(mutex_); | 
 |     bool released_ RTC_GUARDED_BY(mutex_); | 
 |     test::VideoEncoderProxyFactory encoder_factory_; | 
 |     VideoEncoderConfig encoder_config_; | 
 |   } test_encoder(task_queue()); | 
 |  | 
 |   RunBaseTest(&test_encoder); | 
 |  | 
 |   EXPECT_TRUE(test_encoder.IsReleased()); | 
 |   EXPECT_EQ(1u, test_encoder.num_releases()); | 
 | } | 
 |  | 
 | static const size_t kVideoCodecConfigObserverNumberOfTemporalLayers = 3; | 
 | template <typename T> | 
 | class VideoCodecConfigObserver : public test::SendTest, | 
 |                                  public test::FakeEncoder { | 
 |  public: | 
 |   VideoCodecConfigObserver(VideoCodecType video_codec_type, | 
 |                            TaskQueueBase* task_queue) | 
 |       : SendTest(VideoSendStreamTest::kDefaultTimeoutMs), | 
 |         FakeEncoder(Clock::GetRealTimeClock()), | 
 |         video_codec_type_(video_codec_type), | 
 |         stream_(nullptr), | 
 |         encoder_factory_(this), | 
 |         task_queue_(task_queue) { | 
 |     InitCodecSpecifics(); | 
 |   } | 
 |  | 
 |  private: | 
 |   void ModifyVideoConfigs( | 
 |       VideoSendStream::Config* send_config, | 
 |       std::vector<VideoReceiveStream::Config>* receive_configs, | 
 |       VideoEncoderConfig* encoder_config) override { | 
 |     send_config->encoder_settings.encoder_factory = &encoder_factory_; | 
 |     send_config->rtp.payload_name = CodecTypeToPayloadString(video_codec_type_); | 
 |  | 
 |     encoder_config->codec_type = video_codec_type_; | 
 |     encoder_config->encoder_specific_settings = GetEncoderSpecificSettings(); | 
 |     EXPECT_EQ(1u, encoder_config->simulcast_layers.size()); | 
 |     encoder_config->simulcast_layers[0].num_temporal_layers = | 
 |         kVideoCodecConfigObserverNumberOfTemporalLayers; | 
 |     encoder_config_ = encoder_config->Copy(); | 
 |   } | 
 |  | 
 |   void OnVideoStreamsCreated( | 
 |       VideoSendStream* send_stream, | 
 |       const std::vector<VideoReceiveStream*>& receive_streams) override { | 
 |     stream_ = send_stream; | 
 |   } | 
 |  | 
 |   int32_t InitEncode(const VideoCodec* config, | 
 |                      const Settings& settings) override { | 
 |     EXPECT_EQ(video_codec_type_, config->codecType); | 
 |     VerifyCodecSpecifics(*config); | 
 |     int ret = FakeEncoder::InitEncode(config, settings); | 
 |     init_encode_event_.Set(); | 
 |     return ret; | 
 |   } | 
 |  | 
 |   void InitCodecSpecifics(); | 
 |   void VerifyCodecSpecifics(const VideoCodec& config) const; | 
 |   rtc::scoped_refptr<VideoEncoderConfig::EncoderSpecificSettings> | 
 |   GetEncoderSpecificSettings() const; | 
 |  | 
 |   void PerformTest() override { | 
 |     EXPECT_TRUE( | 
 |         init_encode_event_.Wait(VideoSendStreamTest::kDefaultTimeoutMs)); | 
 |     ASSERT_EQ(1, FakeEncoder::GetNumInitializations()) | 
 |         << "VideoEncoder not initialized."; | 
 |  | 
 |     // Change encoder settings to actually trigger reconfiguration. | 
 |     encoder_config_.frame_drop_enabled = !encoder_config_.frame_drop_enabled; | 
 |     encoder_config_.encoder_specific_settings = GetEncoderSpecificSettings(); | 
 |     SendTask(RTC_FROM_HERE, task_queue_, [&]() { | 
 |       stream_->ReconfigureVideoEncoder(std::move(encoder_config_)); | 
 |     }); | 
 |     ASSERT_TRUE( | 
 |         init_encode_event_.Wait(VideoSendStreamTest::kDefaultTimeoutMs)); | 
 |     EXPECT_EQ(2, FakeEncoder::GetNumInitializations()) | 
 |         << "ReconfigureVideoEncoder did not reinitialize the encoder with " | 
 |            "new encoder settings."; | 
 |   } | 
 |  | 
 |   int32_t Encode(const VideoFrame& input_image, | 
 |                  const std::vector<VideoFrameType>* frame_types) override { | 
 |     // Silently skip the encode, FakeEncoder::Encode doesn't produce VP8. | 
 |     return 0; | 
 |   } | 
 |  | 
 |   T encoder_settings_; | 
 |   const VideoCodecType video_codec_type_; | 
 |   rtc::Event init_encode_event_; | 
 |   VideoSendStream* stream_; | 
 |   test::VideoEncoderProxyFactory encoder_factory_; | 
 |   VideoEncoderConfig encoder_config_; | 
 |   TaskQueueBase* task_queue_; | 
 | }; | 
 |  | 
 | template <> | 
 | void VideoCodecConfigObserver<VideoCodecH264>::InitCodecSpecifics() { | 
 |   encoder_settings_ = VideoEncoder::GetDefaultH264Settings(); | 
 | } | 
 |  | 
 | template <> | 
 | void VideoCodecConfigObserver<VideoCodecH264>::VerifyCodecSpecifics( | 
 |     const VideoCodec& config) const { | 
 |   // Check that the number of temporal layers has propagated properly to | 
 |   // VideoCodec. | 
 |   EXPECT_EQ(kVideoCodecConfigObserverNumberOfTemporalLayers, | 
 |             config.H264().numberOfTemporalLayers); | 
 |  | 
 |   for (unsigned char i = 0; i < config.numberOfSimulcastStreams; ++i) { | 
 |     EXPECT_EQ(kVideoCodecConfigObserverNumberOfTemporalLayers, | 
 |               config.simulcastStream[i].numberOfTemporalLayers); | 
 |   } | 
 |  | 
 |   // Set expected temporal layers as they should have been set when | 
 |   // reconfiguring the encoder and not match the set config. | 
 |   VideoCodecH264 encoder_settings = encoder_settings_; | 
 |   encoder_settings.numberOfTemporalLayers = | 
 |       kVideoCodecConfigObserverNumberOfTemporalLayers; | 
 |   EXPECT_EQ( | 
 |       0, memcmp(&config.H264(), &encoder_settings, sizeof(encoder_settings_))); | 
 | } | 
 |  | 
 | template <> | 
 | rtc::scoped_refptr<VideoEncoderConfig::EncoderSpecificSettings> | 
 | VideoCodecConfigObserver<VideoCodecH264>::GetEncoderSpecificSettings() const { | 
 |   return rtc::make_ref_counted<VideoEncoderConfig::H264EncoderSpecificSettings>( | 
 |       encoder_settings_); | 
 | } | 
 |  | 
 | template <> | 
 | void VideoCodecConfigObserver<VideoCodecVP8>::InitCodecSpecifics() { | 
 |   encoder_settings_ = VideoEncoder::GetDefaultVp8Settings(); | 
 | } | 
 |  | 
 | template <> | 
 | void VideoCodecConfigObserver<VideoCodecVP8>::VerifyCodecSpecifics( | 
 |     const VideoCodec& config) const { | 
 |   // Check that the number of temporal layers has propagated properly to | 
 |   // VideoCodec. | 
 |   EXPECT_EQ(kVideoCodecConfigObserverNumberOfTemporalLayers, | 
 |             config.VP8().numberOfTemporalLayers); | 
 |  | 
 |   for (unsigned char i = 0; i < config.numberOfSimulcastStreams; ++i) { | 
 |     EXPECT_EQ(kVideoCodecConfigObserverNumberOfTemporalLayers, | 
 |               config.simulcastStream[i].numberOfTemporalLayers); | 
 |   } | 
 |  | 
 |   // Set expected temporal layers as they should have been set when | 
 |   // reconfiguring the encoder and not match the set config. | 
 |   VideoCodecVP8 encoder_settings = encoder_settings_; | 
 |   encoder_settings.numberOfTemporalLayers = | 
 |       kVideoCodecConfigObserverNumberOfTemporalLayers; | 
 |   EXPECT_EQ( | 
 |       0, memcmp(&config.VP8(), &encoder_settings, sizeof(encoder_settings_))); | 
 | } | 
 |  | 
 | template <> | 
 | rtc::scoped_refptr<VideoEncoderConfig::EncoderSpecificSettings> | 
 | VideoCodecConfigObserver<VideoCodecVP8>::GetEncoderSpecificSettings() const { | 
 |   return rtc::make_ref_counted<VideoEncoderConfig::Vp8EncoderSpecificSettings>( | 
 |       encoder_settings_); | 
 | } | 
 |  | 
 | template <> | 
 | void VideoCodecConfigObserver<VideoCodecVP9>::InitCodecSpecifics() { | 
 |   encoder_settings_ = VideoEncoder::GetDefaultVp9Settings(); | 
 | } | 
 |  | 
 | template <> | 
 | void VideoCodecConfigObserver<VideoCodecVP9>::VerifyCodecSpecifics( | 
 |     const VideoCodec& config) const { | 
 |   // Check that the number of temporal layers has propagated properly to | 
 |   // VideoCodec. | 
 |   EXPECT_EQ(kVideoCodecConfigObserverNumberOfTemporalLayers, | 
 |             config.VP9().numberOfTemporalLayers); | 
 |  | 
 |   for (unsigned char i = 0; i < config.numberOfSimulcastStreams; ++i) { | 
 |     EXPECT_EQ(kVideoCodecConfigObserverNumberOfTemporalLayers, | 
 |               config.simulcastStream[i].numberOfTemporalLayers); | 
 |   } | 
 |  | 
 |   // Set expected temporal layers as they should have been set when | 
 |   // reconfiguring the encoder and not match the set config. | 
 |   VideoCodecVP9 encoder_settings = encoder_settings_; | 
 |   encoder_settings.numberOfTemporalLayers = | 
 |       kVideoCodecConfigObserverNumberOfTemporalLayers; | 
 |   EXPECT_EQ( | 
 |       0, memcmp(&(config.VP9()), &encoder_settings, sizeof(encoder_settings_))); | 
 | } | 
 |  | 
 | template <> | 
 | rtc::scoped_refptr<VideoEncoderConfig::EncoderSpecificSettings> | 
 | VideoCodecConfigObserver<VideoCodecVP9>::GetEncoderSpecificSettings() const { | 
 |   return rtc::make_ref_counted<VideoEncoderConfig::Vp9EncoderSpecificSettings>( | 
 |       encoder_settings_); | 
 | } | 
 |  | 
 | TEST_F(VideoSendStreamTest, EncoderSetupPropagatesVp8Config) { | 
 |   VideoCodecConfigObserver<VideoCodecVP8> test(kVideoCodecVP8, task_queue()); | 
 |   RunBaseTest(&test); | 
 | } | 
 |  | 
 | TEST_F(VideoSendStreamTest, EncoderSetupPropagatesVp9Config) { | 
 |   VideoCodecConfigObserver<VideoCodecVP9> test(kVideoCodecVP9, task_queue()); | 
 |   RunBaseTest(&test); | 
 | } | 
 |  | 
 | // Fails on MSAN: https://bugs.chromium.org/p/webrtc/issues/detail?id=11376. | 
 | #if defined(MEMORY_SANITIZER) | 
 | #define MAYBE_EncoderSetupPropagatesH264Config \ | 
 |   DISABLED_EncoderSetupPropagatesH264Config | 
 | #else | 
 | #define MAYBE_EncoderSetupPropagatesH264Config EncoderSetupPropagatesH264Config | 
 | #endif | 
 | TEST_F(VideoSendStreamTest, MAYBE_EncoderSetupPropagatesH264Config) { | 
 |   VideoCodecConfigObserver<VideoCodecH264> test(kVideoCodecH264, task_queue()); | 
 |   RunBaseTest(&test); | 
 | } | 
 |  | 
 | TEST_F(VideoSendStreamTest, RtcpSenderReportContainsMediaBytesSent) { | 
 |   class RtcpSenderReportTest : public test::SendTest { | 
 |    public: | 
 |     RtcpSenderReportTest() | 
 |         : SendTest(kDefaultTimeoutMs), | 
 |           rtp_packets_sent_(0), | 
 |           media_bytes_sent_(0) {} | 
 |  | 
 |    private: | 
 |     Action OnSendRtp(const uint8_t* packet, size_t length) override { | 
 |       MutexLock lock(&mutex_); | 
 |       RtpPacket rtp_packet; | 
 |       EXPECT_TRUE(rtp_packet.Parse(packet, length)); | 
 |       ++rtp_packets_sent_; | 
 |       media_bytes_sent_ += rtp_packet.payload_size(); | 
 |       return SEND_PACKET; | 
 |     } | 
 |  | 
 |     Action OnSendRtcp(const uint8_t* packet, size_t length) override { | 
 |       MutexLock lock(&mutex_); | 
 |       test::RtcpPacketParser parser; | 
 |       EXPECT_TRUE(parser.Parse(packet, length)); | 
 |  | 
 |       if (parser.sender_report()->num_packets() > 0) { | 
 |         // Only compare sent media bytes if SenderPacketCount matches the | 
 |         // number of sent rtp packets (a new rtp packet could be sent before | 
 |         // the rtcp packet). | 
 |         if (parser.sender_report()->sender_octet_count() > 0 && | 
 |             parser.sender_report()->sender_packet_count() == | 
 |                 rtp_packets_sent_) { | 
 |           EXPECT_EQ(media_bytes_sent_, | 
 |                     parser.sender_report()->sender_octet_count()); | 
 |           observation_complete_.Set(); | 
 |         } | 
 |       } | 
 |  | 
 |       return SEND_PACKET; | 
 |     } | 
 |  | 
 |     void PerformTest() override { | 
 |       EXPECT_TRUE(Wait()) << "Timed out while waiting for RTCP sender report."; | 
 |     } | 
 |  | 
 |     Mutex mutex_; | 
 |     size_t rtp_packets_sent_ RTC_GUARDED_BY(&mutex_); | 
 |     size_t media_bytes_sent_ RTC_GUARDED_BY(&mutex_); | 
 |   } test; | 
 |  | 
 |   RunBaseTest(&test); | 
 | } | 
 |  | 
 | TEST_F(VideoSendStreamTest, TranslatesTwoLayerScreencastToTargetBitrate) { | 
 |   static const int kScreencastMaxTargetBitrateDeltaKbps = 1; | 
 |  | 
 |   class VideoStreamFactory | 
 |       : public VideoEncoderConfig::VideoStreamFactoryInterface { | 
 |    public: | 
 |     VideoStreamFactory() {} | 
 |  | 
 |    private: | 
 |     std::vector<VideoStream> CreateEncoderStreams( | 
 |         int width, | 
 |         int height, | 
 |         const VideoEncoderConfig& encoder_config) override { | 
 |       std::vector<VideoStream> streams = | 
 |           test::CreateVideoStreams(width, height, encoder_config); | 
 |       RTC_CHECK_GT(streams[0].max_bitrate_bps, | 
 |                    kScreencastMaxTargetBitrateDeltaKbps); | 
 |       streams[0].target_bitrate_bps = | 
 |           streams[0].max_bitrate_bps - | 
 |           kScreencastMaxTargetBitrateDeltaKbps * 1000; | 
 |       return streams; | 
 |     } | 
 |   }; | 
 |  | 
 |   class ScreencastTargetBitrateTest : public test::SendTest, | 
 |                                       public test::FakeEncoder { | 
 |    public: | 
 |     ScreencastTargetBitrateTest() | 
 |         : SendTest(kDefaultTimeoutMs), | 
 |           test::FakeEncoder(Clock::GetRealTimeClock()), | 
 |           encoder_factory_(this) {} | 
 |  | 
 |    private: | 
 |     int32_t InitEncode(const VideoCodec* config, | 
 |                        const Settings& settings) override { | 
 |       EXPECT_EQ(config->numberOfSimulcastStreams, 1); | 
 |       EXPECT_EQ(static_cast<unsigned int>(kScreencastMaxTargetBitrateDeltaKbps), | 
 |                 config->simulcastStream[0].maxBitrate - | 
 |                     config->simulcastStream[0].targetBitrate); | 
 |       observation_complete_.Set(); | 
 |       return test::FakeEncoder::InitEncode(config, settings); | 
 |     } | 
 |  | 
 |     void ModifyVideoConfigs( | 
 |         VideoSendStream::Config* send_config, | 
 |         std::vector<VideoReceiveStream::Config>* receive_configs, | 
 |         VideoEncoderConfig* encoder_config) override { | 
 |       send_config->encoder_settings.encoder_factory = &encoder_factory_; | 
 |       EXPECT_EQ(1u, encoder_config->number_of_streams); | 
 |       encoder_config->video_stream_factory = | 
 |           rtc::make_ref_counted<VideoStreamFactory>(); | 
 |       EXPECT_EQ(1u, encoder_config->simulcast_layers.size()); | 
 |       encoder_config->simulcast_layers[0].num_temporal_layers = 2; | 
 |       encoder_config->content_type = VideoEncoderConfig::ContentType::kScreen; | 
 |     } | 
 |  | 
 |     void PerformTest() override { | 
 |       EXPECT_TRUE(Wait()) | 
 |           << "Timed out while waiting for the encoder to be initialized."; | 
 |     } | 
 |     test::VideoEncoderProxyFactory encoder_factory_; | 
 |   } test; | 
 |  | 
 |   RunBaseTest(&test); | 
 | } | 
 |  | 
 | TEST_F(VideoSendStreamTest, ReconfigureBitratesSetsEncoderBitratesCorrectly) { | 
 |   // These are chosen to be "kind of odd" to not be accidentally checked against | 
 |   // default values. | 
 |   static const int kMinBitrateKbps = 137; | 
 |   static const int kStartBitrateKbps = 345; | 
 |   static const int kLowerMaxBitrateKbps = 312; | 
 |   static const int kMaxBitrateKbps = 413; | 
 |   static const int kIncreasedStartBitrateKbps = 451; | 
 |   static const int kIncreasedMaxBitrateKbps = 597; | 
 |   // TODO(bugs.webrtc.org/12058): If these fields trial are on, we get lower | 
 |   // bitrates than expected by this test, due to encoder pushback and subtracted | 
 |   // overhead. | 
 |   webrtc::test::ScopedKeyValueConfig field_trials( | 
 |       field_trials_, | 
 |       "WebRTC-VideoRateControl/bitrate_adjuster:false/" | 
 |       "WebRTC-SendSideBwe-WithOverhead/Disabled/"); | 
 |  | 
 |   class EncoderBitrateThresholdObserver : public test::SendTest, | 
 |                                           public VideoBitrateAllocatorFactory, | 
 |                                           public test::FakeEncoder { | 
 |    public: | 
 |     explicit EncoderBitrateThresholdObserver(TaskQueueBase* task_queue) | 
 |         : SendTest(kDefaultTimeoutMs), | 
 |           FakeEncoder(Clock::GetRealTimeClock()), | 
 |           task_queue_(task_queue), | 
 |           target_bitrate_(0), | 
 |           num_rate_allocator_creations_(0), | 
 |           num_encoder_initializations_(0), | 
 |           call_(nullptr), | 
 |           send_stream_(nullptr), | 
 |           encoder_factory_(this), | 
 |           bitrate_allocator_factory_( | 
 |               CreateBuiltinVideoBitrateAllocatorFactory()) {} | 
 |  | 
 |    private: | 
 |     std::unique_ptr<VideoBitrateAllocator> CreateVideoBitrateAllocator( | 
 |         const VideoCodec& codec) override { | 
 |       EXPECT_GE(codec.startBitrate, codec.minBitrate); | 
 |       EXPECT_LE(codec.startBitrate, codec.maxBitrate); | 
 |       if (num_rate_allocator_creations_ == 0) { | 
 |         EXPECT_EQ(static_cast<unsigned int>(kMinBitrateKbps), codec.minBitrate); | 
 |         EXPECT_EQ(static_cast<unsigned int>(kStartBitrateKbps), | 
 |                   codec.startBitrate); | 
 |         EXPECT_EQ(static_cast<unsigned int>(kMaxBitrateKbps), codec.maxBitrate); | 
 |       } else if (num_rate_allocator_creations_ == 1) { | 
 |         EXPECT_EQ(static_cast<unsigned int>(kLowerMaxBitrateKbps), | 
 |                   codec.maxBitrate); | 
 |         // The start bitrate should be kept (-1) and capped to the max bitrate. | 
 |         // Since this is not an end-to-end call no receiver should have been | 
 |         // returning a REMB that could lower this estimate. | 
 |         EXPECT_EQ(codec.startBitrate, codec.maxBitrate); | 
 |       } else if (num_rate_allocator_creations_ == 2) { | 
 |         EXPECT_EQ(static_cast<unsigned int>(kIncreasedMaxBitrateKbps), | 
 |                   codec.maxBitrate); | 
 |         // The start bitrate will be whatever the rate BitRateController has | 
 |         // currently configured but in the span of the set max and min bitrate. | 
 |       } | 
 |       ++num_rate_allocator_creations_; | 
 |       create_rate_allocator_event_.Set(); | 
 |  | 
 |       return bitrate_allocator_factory_->CreateVideoBitrateAllocator(codec); | 
 |     } | 
 |  | 
 |     int32_t InitEncode(const VideoCodec* codecSettings, | 
 |                        const Settings& settings) override { | 
 |       EXPECT_EQ(0, num_encoder_initializations_); | 
 |       EXPECT_EQ(static_cast<unsigned int>(kMinBitrateKbps), | 
 |                 codecSettings->minBitrate); | 
 |       EXPECT_EQ(static_cast<unsigned int>(kStartBitrateKbps), | 
 |                 codecSettings->startBitrate); | 
 |       EXPECT_EQ(static_cast<unsigned int>(kMaxBitrateKbps), | 
 |                 codecSettings->maxBitrate); | 
 |  | 
 |       ++num_encoder_initializations_; | 
 |  | 
 |       observation_complete_.Set(); | 
 |       init_encode_event_.Set(); | 
 |  | 
 |       return FakeEncoder::InitEncode(codecSettings, settings); | 
 |     } | 
 |  | 
 |     void SetRates(const RateControlParameters& parameters) override { | 
 |       { | 
 |         MutexLock lock(&mutex_); | 
 |         if (target_bitrate_ == parameters.bitrate.get_sum_kbps()) { | 
 |           FakeEncoder::SetRates(parameters); | 
 |           return; | 
 |         } | 
 |         target_bitrate_ = parameters.bitrate.get_sum_kbps(); | 
 |       } | 
 |       bitrate_changed_event_.Set(); | 
 |       FakeEncoder::SetRates(parameters); | 
 |     } | 
 |  | 
 |     void WaitForSetRates(uint32_t expected_bitrate) { | 
 |       // Wait for the expected rate to be set. In some cases there can be | 
 |       // more than one update pending, in which case we keep waiting | 
 |       // until the correct value has been observed. | 
 |       const int64_t start_time = rtc::TimeMillis(); | 
 |       do { | 
 |         MutexLock lock(&mutex_); | 
 |         if (target_bitrate_ == expected_bitrate) { | 
 |           return; | 
 |         } | 
 |       } while (bitrate_changed_event_.Wait( | 
 |           std::max(int64_t{1}, VideoSendStreamTest::kDefaultTimeoutMs - | 
 |                                    (rtc::TimeMillis() - start_time)))); | 
 |       MutexLock lock(&mutex_); | 
 |       EXPECT_EQ(target_bitrate_, expected_bitrate) | 
 |           << "Timed out while waiting encoder rate to be set."; | 
 |     } | 
 |  | 
 |     void ModifySenderBitrateConfig( | 
 |         BitrateConstraints* bitrate_config) override { | 
 |       bitrate_config->min_bitrate_bps = kMinBitrateKbps * 1000; | 
 |       bitrate_config->start_bitrate_bps = kStartBitrateKbps * 1000; | 
 |       bitrate_config->max_bitrate_bps = kMaxBitrateKbps * 1000; | 
 |     } | 
 |  | 
 |     void ModifyVideoConfigs( | 
 |         VideoSendStream::Config* send_config, | 
 |         std::vector<VideoReceiveStream::Config>* receive_configs, | 
 |         VideoEncoderConfig* encoder_config) override { | 
 |       send_config->encoder_settings.encoder_factory = &encoder_factory_; | 
 |       send_config->encoder_settings.bitrate_allocator_factory = this; | 
 |       // Set bitrates lower/higher than min/max to make sure they are properly | 
 |       // capped. | 
 |       encoder_config->max_bitrate_bps = kMaxBitrateKbps * 1000; | 
 |       EXPECT_EQ(1u, encoder_config->simulcast_layers.size()); | 
 |       encoder_config->simulcast_layers[0].min_bitrate_bps = | 
 |           kMinBitrateKbps * 1000; | 
 |       encoder_config_ = encoder_config->Copy(); | 
 |     } | 
 |  | 
 |     void OnCallsCreated(Call* sender_call, Call* receiver_call) override { | 
 |       call_ = sender_call; | 
 |     } | 
 |  | 
 |     void OnVideoStreamsCreated( | 
 |         VideoSendStream* send_stream, | 
 |         const std::vector<VideoReceiveStream*>& receive_streams) override { | 
 |       send_stream_ = send_stream; | 
 |     } | 
 |  | 
 |     void PerformTest() override { | 
 |       ASSERT_TRUE(create_rate_allocator_event_.Wait( | 
 |           VideoSendStreamTest::kDefaultTimeoutMs)) | 
 |           << "Timed out while waiting for rate allocator to be created."; | 
 |       ASSERT_TRUE( | 
 |           init_encode_event_.Wait(VideoSendStreamTest::kDefaultTimeoutMs)) | 
 |           << "Timed out while waiting for encoder to be configured."; | 
 |       WaitForSetRates(kStartBitrateKbps); | 
 |       BitrateConstraints bitrate_config; | 
 |       bitrate_config.start_bitrate_bps = kIncreasedStartBitrateKbps * 1000; | 
 |       bitrate_config.max_bitrate_bps = kIncreasedMaxBitrateKbps * 1000; | 
 |       SendTask(RTC_FROM_HERE, task_queue_, [this, &bitrate_config]() { | 
 |         call_->GetTransportControllerSend()->SetSdpBitrateParameters( | 
 |             bitrate_config); | 
 |       }); | 
 |       // Encoder rate is capped by EncoderConfig max_bitrate_bps. | 
 |       WaitForSetRates(kMaxBitrateKbps); | 
 |       encoder_config_.max_bitrate_bps = kLowerMaxBitrateKbps * 1000; | 
 |       SendTask(RTC_FROM_HERE, task_queue_, [&]() { | 
 |         send_stream_->ReconfigureVideoEncoder(encoder_config_.Copy()); | 
 |       }); | 
 |       ASSERT_TRUE(create_rate_allocator_event_.Wait( | 
 |           VideoSendStreamTest::kDefaultTimeoutMs)); | 
 |       EXPECT_EQ(2, num_rate_allocator_creations_) | 
 |           << "Rate allocator should have been recreated."; | 
 |  | 
 |       WaitForSetRates(kLowerMaxBitrateKbps); | 
 |       EXPECT_EQ(1, num_encoder_initializations_); | 
 |  | 
 |       encoder_config_.max_bitrate_bps = kIncreasedMaxBitrateKbps * 1000; | 
 |       SendTask(RTC_FROM_HERE, task_queue_, [&]() { | 
 |         send_stream_->ReconfigureVideoEncoder(encoder_config_.Copy()); | 
 |       }); | 
 |       ASSERT_TRUE(create_rate_allocator_event_.Wait( | 
 |           VideoSendStreamTest::kDefaultTimeoutMs)); | 
 |       EXPECT_EQ(3, num_rate_allocator_creations_) | 
 |           << "Rate allocator should have been recreated."; | 
 |  | 
 |       // Expected target bitrate is the start bitrate set in the call to | 
 |       // call_->GetTransportControllerSend()->SetSdpBitrateParameters. | 
 |       WaitForSetRates(kIncreasedStartBitrateKbps); | 
 |       EXPECT_EQ(1, num_encoder_initializations_); | 
 |     } | 
 |  | 
 |     TaskQueueBase* const task_queue_; | 
 |     rtc::Event create_rate_allocator_event_; | 
 |     rtc::Event init_encode_event_; | 
 |     rtc::Event bitrate_changed_event_; | 
 |     Mutex mutex_; | 
 |     uint32_t target_bitrate_ RTC_GUARDED_BY(&mutex_); | 
 |  | 
 |     int num_rate_allocator_creations_; | 
 |     int num_encoder_initializations_; | 
 |     webrtc::Call* call_; | 
 |     webrtc::VideoSendStream* send_stream_; | 
 |     test::VideoEncoderProxyFactory encoder_factory_; | 
 |     std::unique_ptr<VideoBitrateAllocatorFactory> bitrate_allocator_factory_; | 
 |     webrtc::VideoEncoderConfig encoder_config_; | 
 |   } test(task_queue()); | 
 |  | 
 |   RunBaseTest(&test); | 
 | } | 
 |  | 
 | TEST_F(VideoSendStreamTest, ReportsSentResolution) { | 
 |   static const size_t kNumStreams = 3; | 
 |   // Unusual resolutions to make sure that they are the ones being reported. | 
 |   static const struct { | 
 |     int width; | 
 |     int height; | 
 |   } kEncodedResolution[kNumStreams] = {{241, 181}, {300, 121}, {121, 221}}; | 
 |   class ScreencastTargetBitrateTest : public test::SendTest, | 
 |                                       public test::FakeEncoder { | 
 |    public: | 
 |     explicit ScreencastTargetBitrateTest(TaskQueueBase* task_queue) | 
 |         : SendTest(kDefaultTimeoutMs), | 
 |           test::FakeEncoder(Clock::GetRealTimeClock()), | 
 |           send_stream_(nullptr), | 
 |           encoder_factory_(this), | 
 |           task_queue_(task_queue) {} | 
 |  | 
 |    private: | 
 |     int32_t Encode(const VideoFrame& input_image, | 
 |                    const std::vector<VideoFrameType>* frame_types) override { | 
 |       CodecSpecificInfo specifics; | 
 |       specifics.codecType = kVideoCodecGeneric; | 
 |  | 
 |       EncodedImage encoded; | 
 |       auto buffer = EncodedImageBuffer::Create(16); | 
 |       memset(buffer->data(), 0, 16); | 
 |       encoded.SetEncodedData(buffer); | 
 |       encoded.SetTimestamp(input_image.timestamp()); | 
 |       encoded.capture_time_ms_ = input_image.render_time_ms(); | 
 |  | 
 |       for (size_t i = 0; i < kNumStreams; ++i) { | 
 |         encoded._frameType = (*frame_types)[i]; | 
 |         encoded._encodedWidth = kEncodedResolution[i].width; | 
 |         encoded._encodedHeight = kEncodedResolution[i].height; | 
 |         encoded.SetSpatialIndex(i); | 
 |         EncodedImageCallback* callback; | 
 |         { | 
 |           MutexLock lock(&mutex_); | 
 |           callback = callback_; | 
 |         } | 
 |         RTC_DCHECK(callback); | 
 |         if (callback->OnEncodedImage(encoded, &specifics).error != | 
 |             EncodedImageCallback::Result::OK) { | 
 |           return -1; | 
 |         } | 
 |       } | 
 |  | 
 |       observation_complete_.Set(); | 
 |       return 0; | 
 |     } | 
 |     void ModifyVideoConfigs( | 
 |         VideoSendStream::Config* send_config, | 
 |         std::vector<VideoReceiveStream::Config>* receive_configs, | 
 |         VideoEncoderConfig* encoder_config) override { | 
 |       send_config->encoder_settings.encoder_factory = &encoder_factory_; | 
 |       EXPECT_EQ(kNumStreams, encoder_config->number_of_streams); | 
 |     } | 
 |  | 
 |     size_t GetNumVideoStreams() const override { return kNumStreams; } | 
 |  | 
 |     void PerformTest() override { | 
 |       EXPECT_TRUE(Wait()) | 
 |           << "Timed out while waiting for the encoder to send one frame."; | 
 |       VideoSendStream::Stats stats; | 
 |       SendTask(RTC_FROM_HERE, task_queue_, | 
 |                [&]() { stats = send_stream_->GetStats(); }); | 
 |  | 
 |       for (size_t i = 0; i < kNumStreams; ++i) { | 
 |         ASSERT_TRUE(stats.substreams.find(kVideoSendSsrcs[i]) != | 
 |                     stats.substreams.end()) | 
 |             << "No stats for SSRC: " << kVideoSendSsrcs[i] | 
 |             << ", stats should exist as soon as frames have been encoded."; | 
 |         VideoSendStream::StreamStats ssrc_stats = | 
 |             stats.substreams[kVideoSendSsrcs[i]]; | 
 |         EXPECT_EQ(kEncodedResolution[i].width, ssrc_stats.width); | 
 |         EXPECT_EQ(kEncodedResolution[i].height, ssrc_stats.height); | 
 |       } | 
 |     } | 
 |  | 
 |     void OnVideoStreamsCreated( | 
 |         VideoSendStream* send_stream, | 
 |         const std::vector<VideoReceiveStream*>& receive_streams) override { | 
 |       send_stream_ = send_stream; | 
 |     } | 
 |  | 
 |     VideoSendStream* send_stream_; | 
 |     test::VideoEncoderProxyFactory encoder_factory_; | 
 |     TaskQueueBase* const task_queue_; | 
 |   } test(task_queue()); | 
 |  | 
 |   RunBaseTest(&test); | 
 | } | 
 |  | 
 | #if defined(RTC_ENABLE_VP9) | 
 | class Vp9HeaderObserver : public test::SendTest { | 
 |  public: | 
 |   Vp9HeaderObserver() | 
 |       : SendTest(VideoSendStreamTest::kLongTimeoutMs), | 
 |         encoder_factory_([]() { return VP9Encoder::Create(); }), | 
 |         vp9_settings_(VideoEncoder::GetDefaultVp9Settings()), | 
 |         packets_sent_(0), | 
 |         frames_sent_(0), | 
 |         expected_width_(0), | 
 |         expected_height_(0) {} | 
 |  | 
 |   virtual void ModifyVideoConfigsHook( | 
 |       VideoSendStream::Config* send_config, | 
 |       std::vector<VideoReceiveStream::Config>* receive_configs, | 
 |       VideoEncoderConfig* encoder_config) {} | 
 |  | 
 |   virtual void InspectHeader(const RTPVideoHeaderVP9& vp9) = 0; | 
 |  | 
 |  private: | 
 |   const int kVp9PayloadType = test::CallTest::kVideoSendPayloadType; | 
 |  | 
 |   void ModifyVideoConfigs( | 
 |       VideoSendStream::Config* send_config, | 
 |       std::vector<VideoReceiveStream::Config>* receive_configs, | 
 |       VideoEncoderConfig* encoder_config) override { | 
 |     send_config->encoder_settings.encoder_factory = &encoder_factory_; | 
 |     send_config->rtp.payload_name = "VP9"; | 
 |     send_config->rtp.payload_type = kVp9PayloadType; | 
 |     ModifyVideoConfigsHook(send_config, receive_configs, encoder_config); | 
 |     encoder_config->encoder_specific_settings = | 
 |         rtc::make_ref_counted<VideoEncoderConfig::Vp9EncoderSpecificSettings>( | 
 |             vp9_settings_); | 
 |     EXPECT_EQ(1u, encoder_config->number_of_streams); | 
 |     EXPECT_EQ(1u, encoder_config->simulcast_layers.size()); | 
 |     encoder_config->simulcast_layers[0].num_temporal_layers = | 
 |         vp9_settings_.numberOfTemporalLayers; | 
 |     encoder_config_ = encoder_config->Copy(); | 
 |   } | 
 |  | 
 |   void ModifyVideoCaptureStartResolution(int* width, | 
 |                                          int* height, | 
 |                                          int* frame_rate) override { | 
 |     expected_width_ = *width; | 
 |     expected_height_ = *height; | 
 |   } | 
 |  | 
 |   void PerformTest() override { | 
 |     bool wait = Wait(); | 
 |     { | 
 |       // In case of time out, OnSendRtp might still access frames_sent_; | 
 |       MutexLock lock(&mutex_); | 
 |       EXPECT_TRUE(wait) << "Test timed out waiting for VP9 packet, num frames " | 
 |                         << frames_sent_; | 
 |     } | 
 |   } | 
 |  | 
 |   Action OnSendRtp(const uint8_t* packet, size_t length) override { | 
 |     RtpPacket rtp_packet; | 
 |     EXPECT_TRUE(rtp_packet.Parse(packet, length)); | 
 |  | 
 |     EXPECT_EQ(kVp9PayloadType, rtp_packet.PayloadType()); | 
 |     rtc::ArrayView<const uint8_t> rtp_payload = rtp_packet.payload(); | 
 |  | 
 |     bool new_packet = packets_sent_ == 0 || | 
 |                       IsNewerSequenceNumber(rtp_packet.SequenceNumber(), | 
 |                                             last_packet_sequence_number_); | 
 |     if (!rtp_payload.empty() && new_packet) { | 
 |       RTPVideoHeader video_header; | 
 |       EXPECT_NE( | 
 |           VideoRtpDepacketizerVp9::ParseRtpPayload(rtp_payload, &video_header), | 
 |           0); | 
 |       EXPECT_EQ(VideoCodecType::kVideoCodecVP9, video_header.codec); | 
 |       // Verify common fields for all configurations. | 
 |       const auto& vp9_header = | 
 |           absl::get<RTPVideoHeaderVP9>(video_header.video_type_header); | 
 |       VerifyCommonHeader(vp9_header); | 
 |       CompareConsecutiveFrames(rtp_packet, video_header); | 
 |       // Verify configuration specific settings. | 
 |       InspectHeader(vp9_header); | 
 |  | 
 |       ++packets_sent_; | 
 |       if (rtp_packet.Marker()) { | 
 |         MutexLock lock(&mutex_); | 
 |         ++frames_sent_; | 
 |       } | 
 |       last_packet_marker_ = rtp_packet.Marker(); | 
 |       last_packet_sequence_number_ = rtp_packet.SequenceNumber(); | 
 |       last_packet_timestamp_ = rtp_packet.Timestamp(); | 
 |       last_vp9_ = vp9_header; | 
 |     } | 
 |     return SEND_PACKET; | 
 |   } | 
 |  | 
 |  protected: | 
 |   bool ContinuousPictureId(const RTPVideoHeaderVP9& vp9) const { | 
 |     if (last_vp9_.picture_id > vp9.picture_id) { | 
 |       return vp9.picture_id == 0;  // Wrap. | 
 |     } else { | 
 |       return vp9.picture_id == last_vp9_.picture_id + 1; | 
 |     } | 
 |   } | 
 |  | 
 |   void VerifySpatialIdxWithinFrame(const RTPVideoHeaderVP9& vp9) const { | 
 |     bool new_layer = vp9.spatial_idx != last_vp9_.spatial_idx; | 
 |     EXPECT_EQ(new_layer, vp9.beginning_of_frame); | 
 |     EXPECT_EQ(new_layer, last_vp9_.end_of_frame); | 
 |     EXPECT_EQ(new_layer ? last_vp9_.spatial_idx + 1 : last_vp9_.spatial_idx, | 
 |               vp9.spatial_idx); | 
 |   } | 
 |  | 
 |   void VerifyFixedTemporalLayerStructure(const RTPVideoHeaderVP9& vp9, | 
 |                                          uint8_t num_layers) const { | 
 |     switch (num_layers) { | 
 |       case 0: | 
 |         VerifyTemporalLayerStructure0(vp9); | 
 |         break; | 
 |       case 1: | 
 |         VerifyTemporalLayerStructure1(vp9); | 
 |         break; | 
 |       case 2: | 
 |         VerifyTemporalLayerStructure2(vp9); | 
 |         break; | 
 |       case 3: | 
 |         VerifyTemporalLayerStructure3(vp9); | 
 |         break; | 
 |       default: | 
 |         RTC_DCHECK_NOTREACHED(); | 
 |     } | 
 |   } | 
 |  | 
 |   void VerifyTemporalLayerStructure0(const RTPVideoHeaderVP9& vp9) const { | 
 |     EXPECT_EQ(kNoTl0PicIdx, vp9.tl0_pic_idx); | 
 |     EXPECT_EQ(kNoTemporalIdx, vp9.temporal_idx);  // no tid | 
 |     // Technically true, but layer indices not available. | 
 |     EXPECT_FALSE(vp9.temporal_up_switch); | 
 |   } | 
 |  | 
 |   void VerifyTemporalLayerStructure1(const RTPVideoHeaderVP9& vp9) const { | 
 |     EXPECT_NE(kNoTl0PicIdx, vp9.tl0_pic_idx); | 
 |     EXPECT_EQ(0, vp9.temporal_idx);  // 0,0,0,... | 
 |   } | 
 |  | 
 |   void VerifyTemporalLayerStructure2(const RTPVideoHeaderVP9& vp9) const { | 
 |     EXPECT_NE(kNoTl0PicIdx, vp9.tl0_pic_idx); | 
 |     EXPECT_GE(vp9.temporal_idx, 0);  // 0,1,0,1,... (tid reset on I-frames). | 
 |     EXPECT_LE(vp9.temporal_idx, 1); | 
 |     EXPECT_TRUE(vp9.temporal_up_switch); | 
 |     if (IsNewPictureId(vp9)) { | 
 |       uint8_t expected_tid = | 
 |           (!vp9.inter_pic_predicted || last_vp9_.temporal_idx == 1) ? 0 : 1; | 
 |       EXPECT_EQ(expected_tid, vp9.temporal_idx); | 
 |     } | 
 |   } | 
 |  | 
 |   void VerifyTemporalLayerStructure3(const RTPVideoHeaderVP9& vp9) const { | 
 |     EXPECT_NE(kNoTl0PicIdx, vp9.tl0_pic_idx); | 
 |     EXPECT_GE(vp9.temporal_idx, 0);  // 0,2,1,2,... (tid reset on I-frames). | 
 |     EXPECT_LE(vp9.temporal_idx, 2); | 
 |     if (IsNewPictureId(vp9) && vp9.inter_pic_predicted) { | 
 |       EXPECT_NE(vp9.temporal_idx, last_vp9_.temporal_idx); | 
 |       EXPECT_TRUE(vp9.temporal_up_switch); | 
 |       switch (vp9.temporal_idx) { | 
 |         case 0: | 
 |           EXPECT_EQ(last_vp9_.temporal_idx, 2); | 
 |           break; | 
 |         case 1: | 
 |           EXPECT_EQ(last_vp9_.temporal_idx, 2); | 
 |           break; | 
 |         case 2: | 
 |           EXPECT_LT(last_vp9_.temporal_idx, 2); | 
 |           break; | 
 |       } | 
 |     } | 
 |   } | 
 |  | 
 |   void VerifyTl0Idx(const RTPVideoHeaderVP9& vp9) const { | 
 |     if (vp9.tl0_pic_idx == kNoTl0PicIdx) | 
 |       return; | 
 |  | 
 |     uint8_t expected_tl0_idx = last_vp9_.tl0_pic_idx; | 
 |     if (vp9.temporal_idx == 0) | 
 |       ++expected_tl0_idx; | 
 |     EXPECT_EQ(expected_tl0_idx, vp9.tl0_pic_idx); | 
 |   } | 
 |  | 
 |   bool IsNewPictureId(const RTPVideoHeaderVP9& vp9) const { | 
 |     return frames_sent_ > 0 && (vp9.picture_id != last_vp9_.picture_id); | 
 |   } | 
 |  | 
 |   // Flexible mode (F=1):    Non-flexible mode (F=0): | 
 |   // | 
 |   //      +-+-+-+-+-+-+-+-+     +-+-+-+-+-+-+-+-+ | 
 |   //      |I|P|L|F|B|E|V|-|     |I|P|L|F|B|E|V|-| | 
 |   //      +-+-+-+-+-+-+-+-+     +-+-+-+-+-+-+-+-+ | 
 |   // I:   |M| PICTURE ID  |  I: |M| PICTURE ID  | | 
 |   //      +-+-+-+-+-+-+-+-+     +-+-+-+-+-+-+-+-+ | 
 |   // M:   | EXTENDED PID  |  M: | EXTENDED PID  | | 
 |   //      +-+-+-+-+-+-+-+-+     +-+-+-+-+-+-+-+-+ | 
 |   // L:   |  T  |U|  S  |D|  L: |  T  |U|  S  |D| | 
 |   //      +-+-+-+-+-+-+-+-+     +-+-+-+-+-+-+-+-+ | 
 |   // P,F: | P_DIFF    |X|N|     |   TL0PICIDX   | | 
 |   //      +-+-+-+-+-+-+-+-+     +-+-+-+-+-+-+-+-+ | 
 |   // X:   |EXTENDED P_DIFF|  V: | SS  ..        | | 
 |   //      +-+-+-+-+-+-+-+-+     +-+-+-+-+-+-+-+-+ | 
 |   // V:   | SS  ..        | | 
 |   //      +-+-+-+-+-+-+-+-+ | 
 |   void VerifyCommonHeader(const RTPVideoHeaderVP9& vp9) const { | 
 |     EXPECT_EQ(kMaxTwoBytePictureId, vp9.max_picture_id);       // M:1 | 
 |     EXPECT_NE(kNoPictureId, vp9.picture_id);                   // I:1 | 
 |     EXPECT_EQ(vp9_settings_.flexibleMode, vp9.flexible_mode);  // F | 
 |  | 
 |     if (vp9_settings_.numberOfSpatialLayers > 1) { | 
 |       EXPECT_LT(vp9.spatial_idx, vp9_settings_.numberOfSpatialLayers); | 
 |     } else if (vp9_settings_.numberOfTemporalLayers > 1) { | 
 |       EXPECT_EQ(vp9.spatial_idx, 0); | 
 |     } else { | 
 |       EXPECT_EQ(vp9.spatial_idx, kNoSpatialIdx); | 
 |     } | 
 |  | 
 |     if (vp9_settings_.numberOfTemporalLayers > 1) { | 
 |       EXPECT_LT(vp9.temporal_idx, vp9_settings_.numberOfTemporalLayers); | 
 |     } else if (vp9_settings_.numberOfSpatialLayers > 1) { | 
 |       EXPECT_EQ(vp9.temporal_idx, 0); | 
 |     } else { | 
 |       EXPECT_EQ(vp9.temporal_idx, kNoTemporalIdx); | 
 |     } | 
 |  | 
 |     if (vp9.ss_data_available)  // V | 
 |       VerifySsData(vp9); | 
 |  | 
 |     if (frames_sent_ == 0) | 
 |       EXPECT_FALSE(vp9.inter_pic_predicted);  // P | 
 |  | 
 |     if (!vp9.inter_pic_predicted) { | 
 |       if (vp9.temporal_idx == kNoTemporalIdx) { | 
 |         EXPECT_FALSE(vp9.temporal_up_switch); | 
 |       } else { | 
 |         EXPECT_EQ(vp9.temporal_idx, 0); | 
 |         EXPECT_TRUE(vp9.temporal_up_switch); | 
 |       } | 
 |     } | 
 |   } | 
 |  | 
 |   // Scalability structure (SS). | 
 |   // | 
 |   //      +-+-+-+-+-+-+-+-+ | 
 |   // V:   | N_S |Y|G|-|-|-| | 
 |   //      +-+-+-+-+-+-+-+-+ | 
 |   // Y:   |    WIDTH      |  N_S + 1 times | 
 |   //      +-+-+-+-+-+-+-+-+ | 
 |   //      |    HEIGHT     | | 
 |   //      +-+-+-+-+-+-+-+-+ | 
 |   // G:   |      N_G      | | 
 |   //      +-+-+-+-+-+-+-+-+ | 
 |   // N_G: |  T  |U| R |-|-|  N_G times | 
 |   //      +-+-+-+-+-+-+-+-+ | 
 |   //      |    P_DIFF     |  R times | 
 |   //      +-+-+-+-+-+-+-+-+ | 
 |   void VerifySsData(const RTPVideoHeaderVP9& vp9) const { | 
 |     EXPECT_TRUE(vp9.ss_data_available);             // V | 
 |     EXPECT_EQ(vp9_settings_.numberOfSpatialLayers,  // N_S + 1 | 
 |               vp9.num_spatial_layers); | 
 |     EXPECT_TRUE(vp9.spatial_layer_resolution_present);  // Y:1 | 
 |     int expected_width = expected_width_; | 
 |     int expected_height = expected_height_; | 
 |     for (int i = static_cast<int>(vp9.num_spatial_layers) - 1; i >= 0; --i) { | 
 |       EXPECT_EQ(expected_width, vp9.width[i]);    // WIDTH | 
 |       EXPECT_EQ(expected_height, vp9.height[i]);  // HEIGHT | 
 |       expected_width /= 2; | 
 |       expected_height /= 2; | 
 |     } | 
 |   } | 
 |  | 
 |   void CompareConsecutiveFrames(const RtpPacket& rtp_packet, | 
 |                                 const RTPVideoHeader& video) const { | 
 |     const auto& vp9_header = | 
 |         absl::get<RTPVideoHeaderVP9>(video.video_type_header); | 
 |  | 
 |     const bool new_temporal_unit = | 
 |         packets_sent_ == 0 || | 
 |         IsNewerTimestamp(rtp_packet.Timestamp(), last_packet_timestamp_); | 
 |     const bool new_frame = | 
 |         new_temporal_unit || last_vp9_.spatial_idx != vp9_header.spatial_idx; | 
 |  | 
 |     EXPECT_EQ(new_frame, video.is_first_packet_in_frame); | 
 |     if (!new_temporal_unit) { | 
 |       EXPECT_FALSE(last_packet_marker_); | 
 |       EXPECT_EQ(last_packet_timestamp_, rtp_packet.Timestamp()); | 
 |       EXPECT_EQ(last_vp9_.picture_id, vp9_header.picture_id); | 
 |       EXPECT_EQ(last_vp9_.temporal_idx, vp9_header.temporal_idx); | 
 |       EXPECT_EQ(last_vp9_.tl0_pic_idx, vp9_header.tl0_pic_idx); | 
 |       VerifySpatialIdxWithinFrame(vp9_header); | 
 |       return; | 
 |     } | 
 |     // New frame. | 
 |     EXPECT_TRUE(vp9_header.beginning_of_frame); | 
 |  | 
 |     // Compare with last packet in previous frame. | 
 |     if (frames_sent_ == 0) | 
 |       return; | 
 |     EXPECT_TRUE(last_vp9_.end_of_frame); | 
 |     EXPECT_TRUE(last_packet_marker_); | 
 |     EXPECT_TRUE(ContinuousPictureId(vp9_header)); | 
 |     VerifyTl0Idx(vp9_header); | 
 |   } | 
 |  | 
 |   test::FunctionVideoEncoderFactory encoder_factory_; | 
 |   VideoCodecVP9 vp9_settings_; | 
 |   webrtc::VideoEncoderConfig encoder_config_; | 
 |   bool last_packet_marker_ = false; | 
 |   uint16_t last_packet_sequence_number_ = 0; | 
 |   uint32_t last_packet_timestamp_ = 0; | 
 |   RTPVideoHeaderVP9 last_vp9_; | 
 |   size_t packets_sent_; | 
 |   Mutex mutex_; | 
 |   size_t frames_sent_; | 
 |   int expected_width_; | 
 |   int expected_height_; | 
 | }; | 
 |  | 
 | class Vp9Test : public VideoSendStreamTest, | 
 |                 public ::testing::WithParamInterface< | 
 |                     ::testing::tuple<Vp9TestParams, bool>> { | 
 |  public: | 
 |   Vp9Test() | 
 |       : params_(::testing::get<0>(GetParam())), | 
 |         use_scalability_mode_identifier_(::testing::get<1>(GetParam())) {} | 
 |  | 
 |  protected: | 
 |   const Vp9TestParams params_; | 
 |   const bool use_scalability_mode_identifier_; | 
 | }; | 
 |  | 
 | INSTANTIATE_TEST_SUITE_P( | 
 |     ScalabilityMode, | 
 |     Vp9Test, | 
 |     ::testing::Combine( | 
 |         ::testing::ValuesIn<Vp9TestParams>( | 
 |             {{"L1T1", 1, 1, InterLayerPredMode::kOn}, | 
 |              {"L1T2", 1, 2, InterLayerPredMode::kOn}, | 
 |              {"L1T3", 1, 3, InterLayerPredMode::kOn}, | 
 |              {"L2T1", 2, 1, InterLayerPredMode::kOn}, | 
 |              {"L2T1_KEY", 2, 1, InterLayerPredMode::kOnKeyPic}, | 
 |              {"L2T2", 2, 2, InterLayerPredMode::kOn}, | 
 |              {"L2T2_KEY", 2, 2, InterLayerPredMode::kOnKeyPic}, | 
 |              {"L2T3", 2, 3, InterLayerPredMode::kOn}, | 
 |              {"L2T3_KEY", 2, 3, InterLayerPredMode::kOnKeyPic}, | 
 |              {"L3T1", 3, 1, InterLayerPredMode::kOn}, | 
 |              {"L3T3", 3, 3, InterLayerPredMode::kOn}, | 
 |              {"L3T3_KEY", 3, 3, InterLayerPredMode::kOnKeyPic}, | 
 |              {"S2T1", 2, 1, InterLayerPredMode::kOff}, | 
 |              {"S3T3", 3, 3, InterLayerPredMode::kOff}}), | 
 |         ::testing::Values(false)),  // use_scalability_mode_identifier | 
 |     [](const ::testing::TestParamInfo<Vp9Test::ParamType>& info) { | 
 |       rtc::StringBuilder sb; | 
 |       sb << std::get<0>(info.param).scalability_mode << "_" | 
 |          << (std::get<1>(info.param) ? "WithIdentifier" : "WithoutIdentifier"); | 
 |       return sb.str(); | 
 |     }); | 
 |  | 
 | TEST_P(Vp9Test, NonFlexMode) { | 
 |   TestVp9NonFlexMode(params_, use_scalability_mode_identifier_); | 
 | } | 
 |  | 
 | void VideoSendStreamTest::TestVp9NonFlexMode( | 
 |     const Vp9TestParams& params, | 
 |     bool use_scalability_mode_identifier) { | 
 |   static const size_t kNumFramesToSend = 100; | 
 |   // Set to < kNumFramesToSend and coprime to length of temporal layer | 
 |   // structures to verify temporal id reset on key frame. | 
 |   static const int kKeyFrameInterval = 31; | 
 |  | 
 |   static const int kWidth = kMinVp9SpatialLayerLongSideLength; | 
 |   static const int kHeight = kMinVp9SpatialLayerShortSideLength; | 
 |   static const float kGoodBitsPerPixel = 0.1f; | 
 |   class NonFlexibleMode : public Vp9HeaderObserver { | 
 |    public: | 
 |     NonFlexibleMode(const Vp9TestParams& params, | 
 |                     bool use_scalability_mode_identifier) | 
 |         : params_(params), | 
 |           use_scalability_mode_identifier_(use_scalability_mode_identifier), | 
 |           l_field_(params.num_temporal_layers > 1 || | 
 |                    params.num_spatial_layers > 1) {} | 
 |  | 
 |     void ModifyVideoConfigsHook( | 
 |         VideoSendStream::Config* send_config, | 
 |         std::vector<VideoReceiveStream::Config>* receive_configs, | 
 |         VideoEncoderConfig* encoder_config) override { | 
 |       encoder_config->codec_type = kVideoCodecVP9; | 
 |       int bitrate_bps = 0; | 
 |       for (int sl_idx = 0; sl_idx < params_.num_spatial_layers; ++sl_idx) { | 
 |         const int width = kWidth << sl_idx; | 
 |         const int height = kHeight << sl_idx; | 
 |         const float bpp = kGoodBitsPerPixel / (1 << sl_idx); | 
 |         bitrate_bps += static_cast<int>(width * height * bpp * 30); | 
 |       } | 
 |       encoder_config->max_bitrate_bps = bitrate_bps * 2; | 
 |  | 
 |       EXPECT_EQ(1u, encoder_config->number_of_streams); | 
 |       EXPECT_EQ(1u, encoder_config->simulcast_layers.size()); | 
 |  | 
 |       encoder_config->frame_drop_enabled = false; | 
 |  | 
 |       vp9_settings_.flexibleMode = false; | 
 |       vp9_settings_.automaticResizeOn = false; | 
 |       vp9_settings_.keyFrameInterval = kKeyFrameInterval; | 
 |       if (!use_scalability_mode_identifier_) { | 
 |         vp9_settings_.numberOfTemporalLayers = params_.num_temporal_layers; | 
 |         vp9_settings_.numberOfSpatialLayers = params_.num_spatial_layers; | 
 |         vp9_settings_.interLayerPred = params_.inter_layer_pred; | 
 |       } else { | 
 |         encoder_config->simulcast_layers[0].scalability_mode = | 
 |             ScalabilityModeFromString(params_.scalability_mode); | 
 |       } | 
 |     } | 
 |  | 
 |     void ModifyVideoCaptureStartResolution(int* width, | 
 |                                            int* height, | 
 |                                            int* frame_rate) override { | 
 |       expected_width_ = kWidth << (params_.num_spatial_layers - 1); | 
 |       expected_height_ = kHeight << (params_.num_spatial_layers - 1); | 
 |       *width = expected_width_; | 
 |       *height = expected_height_; | 
 |     } | 
 |  | 
 |     void InspectHeader(const RTPVideoHeaderVP9& vp9) override { | 
 |       bool ss_data_expected = !vp9.inter_pic_predicted && | 
 |                               vp9.beginning_of_frame && | 
 |                               !vp9.inter_layer_predicted; | 
 |       EXPECT_EQ(ss_data_expected, vp9.ss_data_available); | 
 |  | 
 |       bool is_key_frame = frames_sent_ % kKeyFrameInterval == 0; | 
 |       if (params_.num_spatial_layers > 1) { | 
 |         switch (params_.inter_layer_pred) { | 
 |           case InterLayerPredMode::kOff: | 
 |             EXPECT_FALSE(vp9.inter_layer_predicted); | 
 |             break; | 
 |           case InterLayerPredMode::kOn: | 
 |             EXPECT_EQ(vp9.spatial_idx > 0, vp9.inter_layer_predicted); | 
 |             break; | 
 |           case InterLayerPredMode::kOnKeyPic: | 
 |             EXPECT_EQ(is_key_frame && vp9.spatial_idx > 0, | 
 |                       vp9.inter_layer_predicted); | 
 |             break; | 
 |         } | 
 |       } else { | 
 |         EXPECT_FALSE(vp9.inter_layer_predicted); | 
 |       } | 
 |  | 
 |       EXPECT_EQ(is_key_frame, !vp9.inter_pic_predicted); | 
 |  | 
 |       if (IsNewPictureId(vp9)) { | 
 |         if (params_.num_temporal_layers == 1 && | 
 |             params_.num_spatial_layers == 1) { | 
 |           EXPECT_EQ(kNoSpatialIdx, vp9.spatial_idx); | 
 |         } else { | 
 |           EXPECT_EQ(0, vp9.spatial_idx); | 
 |         } | 
 |         if (params_.num_spatial_layers > 1) | 
 |           EXPECT_EQ(params_.num_spatial_layers - 1, last_vp9_.spatial_idx); | 
 |       } | 
 |  | 
 |       VerifyFixedTemporalLayerStructure( | 
 |           vp9, l_field_ ? params_.num_temporal_layers : 0); | 
 |  | 
 |       if (frames_sent_ > kNumFramesToSend) | 
 |         observation_complete_.Set(); | 
 |     } | 
 |     const Vp9TestParams params_; | 
 |     const bool use_scalability_mode_identifier_; | 
 |     const bool l_field_; | 
 |  | 
 |    private: | 
 |     void ModifySenderBitrateConfig( | 
 |         BitrateConstraints* bitrate_config) override { | 
 |       const int kBitrateBps = 800000; | 
 |       bitrate_config->min_bitrate_bps = kBitrateBps; | 
 |       bitrate_config->start_bitrate_bps = kBitrateBps; | 
 |     } | 
 |   } test(params, use_scalability_mode_identifier); | 
 |  | 
 |   RunBaseTest(&test); | 
 | } | 
 |  | 
 | TEST_F(VideoSendStreamTest, Vp9NonFlexModeSmallResolution) { | 
 |   static const size_t kNumFramesToSend = 50; | 
 |   static const int kWidth = 4; | 
 |   static const int kHeight = 4; | 
 |   class NonFlexibleModeResolution : public Vp9HeaderObserver { | 
 |     void ModifyVideoConfigsHook( | 
 |         VideoSendStream::Config* send_config, | 
 |         std::vector<VideoReceiveStream::Config>* receive_configs, | 
 |         VideoEncoderConfig* encoder_config) override { | 
 |       encoder_config->codec_type = kVideoCodecVP9; | 
 |       vp9_settings_.flexibleMode = false; | 
 |       vp9_settings_.numberOfTemporalLayers = 1; | 
 |       vp9_settings_.numberOfSpatialLayers = 1; | 
 |  | 
 |       EXPECT_EQ(1u, encoder_config->number_of_streams); | 
 |     } | 
 |  | 
 |     void InspectHeader(const RTPVideoHeaderVP9& vp9_header) override { | 
 |       if (frames_sent_ > kNumFramesToSend) | 
 |         observation_complete_.Set(); | 
 |     } | 
 |  | 
 |     void ModifyVideoCaptureStartResolution(int* width, | 
 |                                            int* height, | 
 |                                            int* frame_rate) override { | 
 |       expected_width_ = kWidth; | 
 |       expected_height_ = kHeight; | 
 |       *width = kWidth; | 
 |       *height = kHeight; | 
 |     } | 
 |   } test; | 
 |  | 
 |   RunBaseTest(&test); | 
 | } | 
 |  | 
 | #if defined(WEBRTC_ANDROID) | 
 | // Crashes on Android; bugs.webrtc.org/7401 | 
 | #define MAYBE_Vp9FlexModeRefCount DISABLED_Vp9FlexModeRefCount | 
 | #else | 
 | // TODO(webrtc:9270): Support of flexible mode is temporarily disabled. Enable | 
 | // the test after webrtc:9270 is implemented. | 
 | #define MAYBE_Vp9FlexModeRefCount DISABLED_Vp9FlexModeRefCount | 
 | // #define MAYBE_Vp9FlexModeRefCount Vp9FlexModeRefCount | 
 | #endif | 
 | TEST_F(VideoSendStreamTest, MAYBE_Vp9FlexModeRefCount) { | 
 |   class FlexibleMode : public Vp9HeaderObserver { | 
 |     void ModifyVideoConfigsHook( | 
 |         VideoSendStream::Config* send_config, | 
 |         std::vector<VideoReceiveStream::Config>* receive_configs, | 
 |         VideoEncoderConfig* encoder_config) override { | 
 |       encoder_config->codec_type = kVideoCodecVP9; | 
 |       encoder_config->content_type = VideoEncoderConfig::ContentType::kScreen; | 
 |       vp9_settings_.flexibleMode = true; | 
 |       vp9_settings_.numberOfTemporalLayers = 1; | 
 |       vp9_settings_.numberOfSpatialLayers = 2; | 
 |     } | 
 |  | 
 |     void InspectHeader(const RTPVideoHeaderVP9& vp9_header) override { | 
 |       EXPECT_TRUE(vp9_header.flexible_mode); | 
 |       EXPECT_EQ(kNoTl0PicIdx, vp9_header.tl0_pic_idx); | 
 |       if (vp9_header.inter_pic_predicted) { | 
 |         EXPECT_GT(vp9_header.num_ref_pics, 0u); | 
 |         observation_complete_.Set(); | 
 |       } | 
 |     } | 
 |   } test; | 
 |  | 
 |   RunBaseTest(&test); | 
 | } | 
 | #endif  // defined(RTC_ENABLE_VP9) | 
 |  | 
 | void VideoSendStreamTest::TestRequestSourceRotateVideo( | 
 |     bool support_orientation_ext) { | 
 |   CreateSenderCall(); | 
 |  | 
 |   test::NullTransport transport; | 
 |   CreateSendConfig(1, 0, 0, &transport); | 
 |   GetVideoSendConfig()->rtp.extensions.clear(); | 
 |   if (support_orientation_ext) { | 
 |     GetVideoSendConfig()->rtp.extensions.push_back( | 
 |         RtpExtension(RtpExtension::kVideoRotationUri, 1)); | 
 |   } | 
 |  | 
 |   CreateVideoStreams(); | 
 |   test::FrameForwarder forwarder; | 
 |   GetVideoSendStream()->SetSource(&forwarder, | 
 |                                   DegradationPreference::MAINTAIN_FRAMERATE); | 
 |  | 
 |   EXPECT_TRUE(forwarder.sink_wants().rotation_applied != | 
 |               support_orientation_ext); | 
 |  | 
 |   DestroyStreams(); | 
 | } | 
 |  | 
 | TEST_F(VideoSendStreamTest, | 
 |        RequestSourceRotateIfVideoOrientationExtensionNotSupported) { | 
 |   TestRequestSourceRotateVideo(false); | 
 | } | 
 |  | 
 | TEST_F(VideoSendStreamTest, | 
 |        DoNotRequestsRotationIfVideoOrientationExtensionSupported) { | 
 |   TestRequestSourceRotateVideo(true); | 
 | } | 
 |  | 
 | TEST_F(VideoSendStreamTest, EncoderConfigMaxFramerateReportedToSource) { | 
 |   static const int kMaxFps = 22; | 
 |   class FpsObserver : public test::SendTest, | 
 |                       public test::FrameGeneratorCapturer::SinkWantsObserver { | 
 |    public: | 
 |     FpsObserver() : SendTest(kDefaultTimeoutMs) {} | 
 |  | 
 |     void OnFrameGeneratorCapturerCreated( | 
 |         test::FrameGeneratorCapturer* frame_generator_capturer) override { | 
 |       frame_generator_capturer->SetSinkWantsObserver(this); | 
 |     } | 
 |  | 
 |     void OnSinkWantsChanged(rtc::VideoSinkInterface<VideoFrame>* sink, | 
 |                             const rtc::VideoSinkWants& wants) override { | 
 |       if (wants.max_framerate_fps == kMaxFps) | 
 |         observation_complete_.Set(); | 
 |     } | 
 |  | 
 |     void ModifyVideoConfigs( | 
 |         VideoSendStream::Config* send_config, | 
 |         std::vector<VideoReceiveStream::Config>* receive_configs, | 
 |         VideoEncoderConfig* encoder_config) override { | 
 |       encoder_config->simulcast_layers[0].max_framerate = kMaxFps; | 
 |     } | 
 |  | 
 |     void PerformTest() override { | 
 |       EXPECT_TRUE(Wait()) << "Timed out while waiting for fps to be reported."; | 
 |     } | 
 |   } test; | 
 |  | 
 |   RunBaseTest(&test); | 
 | } | 
 |  | 
 | // This test verifies that overhead is removed from the bandwidth estimate by | 
 | // testing that the maximum possible target payload rate is smaller than the | 
 | // maximum bandwidth estimate by the overhead rate. | 
 | TEST_F(VideoSendStreamTest, RemoveOverheadFromBandwidth) { | 
 |   test::ScopedFieldTrials override_field_trials( | 
 |       "WebRTC-SendSideBwe-WithOverhead/Enabled/"); | 
 |   class RemoveOverheadFromBandwidthTest : public test::EndToEndTest, | 
 |                                           public test::FakeEncoder { | 
 |    public: | 
 |     explicit RemoveOverheadFromBandwidthTest(TaskQueueBase* task_queue) | 
 |         : EndToEndTest(test::CallTest::kDefaultTimeoutMs), | 
 |           FakeEncoder(Clock::GetRealTimeClock()), | 
 |           task_queue_(task_queue), | 
 |           encoder_factory_(this), | 
 |           call_(nullptr), | 
 |           max_bitrate_bps_(0), | 
 |           first_packet_sent_(false) {} | 
 |  | 
 |     void SetRates(const RateControlParameters& parameters) override { | 
 |       MutexLock lock(&mutex_); | 
 |       // Wait for the first sent packet so that videosendstream knows | 
 |       // rtp_overhead. | 
 |       if (first_packet_sent_) { | 
 |         max_bitrate_bps_ = parameters.bitrate.get_sum_bps(); | 
 |         bitrate_changed_event_.Set(); | 
 |       } | 
 |       return FakeEncoder::SetRates(parameters); | 
 |     } | 
 |  | 
 |     void OnCallsCreated(Call* sender_call, Call* receiver_call) override { | 
 |       call_ = sender_call; | 
 |     } | 
 |  | 
 |     void ModifyVideoConfigs( | 
 |         VideoSendStream::Config* send_config, | 
 |         std::vector<VideoReceiveStream::Config>* receive_configs, | 
 |         VideoEncoderConfig* encoder_config) override { | 
 |       send_config->rtp.max_packet_size = 1200; | 
 |       send_config->encoder_settings.encoder_factory = &encoder_factory_; | 
 |       EXPECT_FALSE(send_config->rtp.extensions.empty()); | 
 |     } | 
 |  | 
 |     Action OnSendRtp(const uint8_t* packet, size_t length) override { | 
 |       MutexLock lock(&mutex_); | 
 |       first_packet_sent_ = true; | 
 |       return SEND_PACKET; | 
 |     } | 
 |  | 
 |     void PerformTest() override { | 
 |       BitrateConstraints bitrate_config; | 
 |       constexpr int kStartBitrateBps = 60000; | 
 |       constexpr int kMaxBitrateBps = 60000; | 
 |       constexpr int kMinBitrateBps = 10000; | 
 |       bitrate_config.start_bitrate_bps = kStartBitrateBps; | 
 |       bitrate_config.max_bitrate_bps = kMaxBitrateBps; | 
 |       bitrate_config.min_bitrate_bps = kMinBitrateBps; | 
 |       SendTask(RTC_FROM_HERE, task_queue_, [this, &bitrate_config]() { | 
 |         call_->GetTransportControllerSend()->SetSdpBitrateParameters( | 
 |             bitrate_config); | 
 |         call_->GetTransportControllerSend()->OnTransportOverheadChanged(40); | 
 |       }); | 
 |  | 
 |       // At a bitrate of 60kbps with a packet size of 1200B video and an | 
 |       // overhead of 40B per packet video produces 2240bps overhead. | 
 |       // So the encoder BW should be set to 57760bps. | 
 |       EXPECT_TRUE( | 
 |           bitrate_changed_event_.Wait(VideoSendStreamTest::kDefaultTimeoutMs)); | 
 |       { | 
 |         MutexLock lock(&mutex_); | 
 |         EXPECT_LE(max_bitrate_bps_, 57760u); | 
 |       } | 
 |     } | 
 |  | 
 |    private: | 
 |     TaskQueueBase* const task_queue_; | 
 |     test::VideoEncoderProxyFactory encoder_factory_; | 
 |     Call* call_; | 
 |     Mutex mutex_; | 
 |     uint32_t max_bitrate_bps_ RTC_GUARDED_BY(&mutex_); | 
 |     bool first_packet_sent_ RTC_GUARDED_BY(&mutex_); | 
 |     rtc::Event bitrate_changed_event_; | 
 |   } test(task_queue()); | 
 |   RunBaseTest(&test); | 
 | } | 
 |  | 
 | class PacingFactorObserver : public test::SendTest { | 
 |  public: | 
 |   PacingFactorObserver(bool configure_send_side, | 
 |                        absl::optional<float> expected_pacing_factor) | 
 |       : test::SendTest(VideoSendStreamTest::kDefaultTimeoutMs), | 
 |         configure_send_side_(configure_send_side), | 
 |         expected_pacing_factor_(expected_pacing_factor) {} | 
 |  | 
 |   void ModifyVideoConfigs( | 
 |       VideoSendStream::Config* send_config, | 
 |       std::vector<VideoReceiveStream::Config>* receive_configs, | 
 |       VideoEncoderConfig* encoder_config) override { | 
 |     // Check if send-side bwe extension is already present, and remove it if | 
 |     // it is not desired. | 
 |     bool has_send_side = false; | 
 |     for (auto it = send_config->rtp.extensions.begin(); | 
 |          it != send_config->rtp.extensions.end(); ++it) { | 
 |       if (it->uri == RtpExtension::kTransportSequenceNumberUri) { | 
 |         if (configure_send_side_) { | 
 |           has_send_side = true; | 
 |         } else { | 
 |           send_config->rtp.extensions.erase(it); | 
 |         } | 
 |         break; | 
 |       } | 
 |     } | 
 |  | 
 |     if (configure_send_side_ && !has_send_side) { | 
 |       rtc::UniqueNumberGenerator<int> unique_id_generator; | 
 |       unique_id_generator.AddKnownId(0);  // First valid RTP extension ID is 1. | 
 |       for (const RtpExtension& extension : send_config->rtp.extensions) { | 
 |         unique_id_generator.AddKnownId(extension.id); | 
 |       } | 
 |       // Want send side, not present by default, so add it. | 
 |       send_config->rtp.extensions.emplace_back( | 
 |           RtpExtension::kTransportSequenceNumberUri, unique_id_generator()); | 
 |     } | 
 |  | 
 |     // ALR only enabled for screenshare. | 
 |     encoder_config->content_type = VideoEncoderConfig::ContentType::kScreen; | 
 |   } | 
 |  | 
 |   void OnVideoStreamsCreated( | 
 |       VideoSendStream* send_stream, | 
 |       const std::vector<VideoReceiveStream*>& receive_streams) override { | 
 |     auto internal_send_peer = test::VideoSendStreamPeer(send_stream); | 
 |     // Video streams created, check that pacing factor is correctly configured. | 
 |     EXPECT_EQ(expected_pacing_factor_, | 
 |               internal_send_peer.GetPacingFactorOverride()); | 
 |     observation_complete_.Set(); | 
 |   } | 
 |  | 
 |   void PerformTest() override { | 
 |     EXPECT_TRUE(Wait()) << "Timed out while waiting for stream creation."; | 
 |   } | 
 |  | 
 |  private: | 
 |   const bool configure_send_side_; | 
 |   const absl::optional<float> expected_pacing_factor_; | 
 | }; | 
 |  | 
 | std::string GetAlrProbingExperimentString() { | 
 |   return std::string( | 
 |              AlrExperimentSettings::kScreenshareProbingBweExperimentName) + | 
 |          "/1.0,2875,80,40,-60,3/"; | 
 | } | 
 | const float kAlrProbingExperimentPaceMultiplier = 1.0f; | 
 |  | 
 | TEST_F(VideoSendStreamTest, AlrConfiguredWhenSendSideOn) { | 
 |   test::ScopedFieldTrials alr_experiment(GetAlrProbingExperimentString()); | 
 |   // Send-side bwe on, use pacing factor from `kAlrProbingExperiment` above. | 
 |   PacingFactorObserver test_with_send_side(true, | 
 |                                            kAlrProbingExperimentPaceMultiplier); | 
 |   RunBaseTest(&test_with_send_side); | 
 | } | 
 |  | 
 | TEST_F(VideoSendStreamTest, AlrNotConfiguredWhenSendSideOff) { | 
 |   test::ScopedFieldTrials alr_experiment(GetAlrProbingExperimentString()); | 
 |   // Send-side bwe off, use configuration should not be overridden. | 
 |   PacingFactorObserver test_without_send_side(false, absl::nullopt); | 
 |   RunBaseTest(&test_without_send_side); | 
 | } | 
 |  | 
 | // Test class takes as argument a function pointer to reset the send | 
 | // stream and call OnVideoStreamsCreated. This is necessary since you cannot | 
 | // change the content type of a VideoSendStream, you need to recreate it. | 
 | // Stopping and recreating the stream can only be done on the main thread and in | 
 | // the context of VideoSendStreamTest (not BaseTest). The test switches from | 
 | // realtime to screenshare and back. | 
 | template <typename T> | 
 | class ContentSwitchTest : public test::SendTest { | 
 |  public: | 
 |   enum class StreamState { | 
 |     kBeforeSwitch = 0, | 
 |     kInScreenshare = 1, | 
 |     kAfterSwitchBack = 2, | 
 |   }; | 
 |   static const uint32_t kMinPacketsToSend = 50; | 
 |  | 
 |   explicit ContentSwitchTest(T* stream_reset_fun, TaskQueueBase* task_queue) | 
 |       : SendTest(test::CallTest::kDefaultTimeoutMs), | 
 |         call_(nullptr), | 
 |         state_(StreamState::kBeforeSwitch), | 
 |         send_stream_(nullptr), | 
 |         send_stream_config_(nullptr), | 
 |         packets_sent_(0), | 
 |         stream_resetter_(stream_reset_fun), | 
 |         task_queue_(task_queue) { | 
 |     RTC_DCHECK(stream_resetter_); | 
 |   } | 
 |  | 
 |   void OnVideoStreamsCreated( | 
 |       VideoSendStream* send_stream, | 
 |       const std::vector<VideoReceiveStream*>& receive_streams) override { | 
 |     MutexLock lock(&mutex_); | 
 |     send_stream_ = send_stream; | 
 |   } | 
 |  | 
 |   void ModifyVideoConfigs( | 
 |       VideoSendStream::Config* send_config, | 
 |       std::vector<VideoReceiveStream::Config>* receive_configs, | 
 |       VideoEncoderConfig* encoder_config) override { | 
 |     RTC_DCHECK_EQ(1, encoder_config->number_of_streams); | 
 |     encoder_config->min_transmit_bitrate_bps = 0; | 
 |     encoder_config->content_type = | 
 |         VideoEncoderConfig::ContentType::kRealtimeVideo; | 
 |     send_stream_config_ = send_config->Copy(); | 
 |     encoder_config_ = encoder_config->Copy(); | 
 |   } | 
 |  | 
 |   void OnCallsCreated(Call* sender_call, Call* receiver_call) override { | 
 |     call_ = sender_call; | 
 |   } | 
 |  | 
 |   void OnStreamsStopped() override { | 
 |     MutexLock lock(&mutex_); | 
 |     done_ = true; | 
 |   } | 
 |  | 
 |   Action OnSendRtp(const uint8_t* packet, size_t length) override { | 
 |     task_queue_->PostTask(ToQueuedTask([this]() { | 
 |       MutexLock lock(&mutex_); | 
 |       if (done_) | 
 |         return; | 
 |  | 
 |       auto internal_send_peer = test::VideoSendStreamPeer(send_stream_); | 
 |       float pacing_factor = | 
 |           internal_send_peer.GetPacingFactorOverride().value_or(0.0f); | 
 |       float expected_pacing_factor = 1.1;  // Strict pacing factor. | 
 |       VideoSendStream::Stats stats = send_stream_->GetStats(); | 
 |       if (stats.content_type == webrtc::VideoContentType::SCREENSHARE) { | 
 |         expected_pacing_factor = 1.0f;  // Currently used pacing factor in ALR. | 
 |       } | 
 |  | 
 |       EXPECT_NEAR(expected_pacing_factor, pacing_factor, 1e-6); | 
 |  | 
 |       // Wait until at least kMinPacketsToSend packets to be sent, so that | 
 |       // some frames would be encoded. | 
 |       if (++packets_sent_ < kMinPacketsToSend) | 
 |         return; | 
 |  | 
 |       if (state_ != StreamState::kAfterSwitchBack) { | 
 |         // We've sent kMinPacketsToSend packets, switch the content type and | 
 |         // move move to the next state. Note that we need to recreate the stream | 
 |         // if changing content type. | 
 |         packets_sent_ = 0; | 
 |         if (encoder_config_.content_type == | 
 |             VideoEncoderConfig::ContentType::kRealtimeVideo) { | 
 |           encoder_config_.content_type = | 
 |               VideoEncoderConfig::ContentType::kScreen; | 
 |         } else { | 
 |           encoder_config_.content_type = | 
 |               VideoEncoderConfig::ContentType::kRealtimeVideo; | 
 |         } | 
 |         switch (state_) { | 
 |           case StreamState::kBeforeSwitch: | 
 |             state_ = StreamState::kInScreenshare; | 
 |             break; | 
 |           case StreamState::kInScreenshare: | 
 |             state_ = StreamState::kAfterSwitchBack; | 
 |             break; | 
 |           case StreamState::kAfterSwitchBack: | 
 |             RTC_DCHECK_NOTREACHED(); | 
 |             break; | 
 |         } | 
 |         content_switch_event_.Set(); | 
 |         return; | 
 |       } | 
 |       observation_complete_.Set(); | 
 |     })); | 
 |  | 
 |     return SEND_PACKET; | 
 |   } | 
 |  | 
 |   void PerformTest() override { | 
 |     while (GetStreamState() != StreamState::kAfterSwitchBack) { | 
 |       ASSERT_TRUE( | 
 |           content_switch_event_.Wait(test::CallTest::kDefaultTimeoutMs)); | 
 |       (*stream_resetter_)(send_stream_config_, encoder_config_, this); | 
 |     } | 
 |  | 
 |     ASSERT_TRUE(Wait()) | 
 |         << "Timed out waiting for a frame sent after switch back"; | 
 |   } | 
 |  | 
 |  private: | 
 |   StreamState GetStreamState() { | 
 |     MutexLock lock(&mutex_); | 
 |     return state_; | 
 |   } | 
 |  | 
 |   Mutex mutex_; | 
 |   rtc::Event content_switch_event_; | 
 |   Call* call_; | 
 |   bool done_ RTC_GUARDED_BY(mutex_) = false; | 
 |   StreamState state_ RTC_GUARDED_BY(mutex_); | 
 |   VideoSendStream* send_stream_ RTC_GUARDED_BY(mutex_); | 
 |   VideoSendStream::Config send_stream_config_; | 
 |   VideoEncoderConfig encoder_config_; | 
 |   uint32_t packets_sent_ RTC_GUARDED_BY(mutex_); | 
 |   T* stream_resetter_; | 
 |   TaskQueueBase* task_queue_; | 
 | }; | 
 |  | 
 | TEST_F(VideoSendStreamTest, SwitchesToScreenshareAndBack) { | 
 |   auto reset_fun = [this](const VideoSendStream::Config& send_stream_config, | 
 |                           const VideoEncoderConfig& encoder_config, | 
 |                           test::BaseTest* test) { | 
 |     SendTask(RTC_FROM_HERE, task_queue(), | 
 |              [this, &send_stream_config, &encoder_config, &test]() { | 
 |                Stop(); | 
 |                DestroyVideoSendStreams(); | 
 |                SetVideoSendConfig(send_stream_config); | 
 |                SetVideoEncoderConfig(encoder_config); | 
 |                CreateVideoSendStreams(); | 
 |                SetVideoDegradation(DegradationPreference::MAINTAIN_RESOLUTION); | 
 |                test->OnVideoStreamsCreated(GetVideoSendStream(), | 
 |                                            video_receive_streams_); | 
 |                Start(); | 
 |              }); | 
 |   }; | 
 |   ContentSwitchTest<decltype(reset_fun)> test(&reset_fun, task_queue()); | 
 |   RunBaseTest(&test); | 
 | } | 
 |  | 
 | void VideoSendStreamTest::TestTemporalLayers( | 
 |     VideoEncoderFactory* encoder_factory, | 
 |     const std::string& payload_name, | 
 |     const std::vector<int>& num_temporal_layers, | 
 |     const std::vector<ScalabilityMode>& scalability_mode) { | 
 |   static constexpr int kMaxBitrateBps = 1000000; | 
 |   static constexpr int kMinFramesToObservePerStream = 8; | 
 |  | 
 |   class TemporalLayerObserver | 
 |       : public test::EndToEndTest, | 
 |         public test::FrameGeneratorCapturer::SinkWantsObserver { | 
 |    public: | 
 |     TemporalLayerObserver(VideoEncoderFactory* encoder_factory, | 
 |                           const std::string& payload_name, | 
 |                           const std::vector<int>& num_temporal_layers, | 
 |                           const std::vector<ScalabilityMode>& scalability_mode) | 
 |         : EndToEndTest(kDefaultTimeoutMs), | 
 |           encoder_factory_(encoder_factory), | 
 |           payload_name_(payload_name), | 
 |           num_temporal_layers_(num_temporal_layers), | 
 |           scalability_mode_(scalability_mode), | 
 |           depacketizer_(CreateVideoRtpDepacketizer( | 
 |               PayloadStringToCodecType(payload_name))) {} | 
 |  | 
 |    private: | 
 |     void OnFrameGeneratorCapturerCreated( | 
 |         test::FrameGeneratorCapturer* frame_generator_capturer) override { | 
 |       frame_generator_capturer->ChangeResolution(640, 360); | 
 |     } | 
 |  | 
 |     void OnSinkWantsChanged(rtc::VideoSinkInterface<VideoFrame>* sink, | 
 |                             const rtc::VideoSinkWants& wants) override {} | 
 |  | 
 |     void ModifySenderBitrateConfig( | 
 |         BitrateConstraints* bitrate_config) override { | 
 |       bitrate_config->start_bitrate_bps = kMaxBitrateBps / 2; | 
 |     } | 
 |  | 
 |     size_t GetNumVideoStreams() const override { | 
 |       if (scalability_mode_.empty()) { | 
 |         return num_temporal_layers_.size(); | 
 |       } else { | 
 |         return scalability_mode_.size(); | 
 |       } | 
 |     } | 
 |  | 
 |     void ModifyVideoConfigs( | 
 |         VideoSendStream::Config* send_config, | 
 |         std::vector<VideoReceiveStream::Config>* receive_configs, | 
 |         VideoEncoderConfig* encoder_config) override { | 
 |       send_config->encoder_settings.encoder_factory = encoder_factory_; | 
 |       send_config->rtp.payload_name = payload_name_; | 
 |       send_config->rtp.payload_type = test::CallTest::kVideoSendPayloadType; | 
 |       encoder_config->video_format.name = payload_name_; | 
 |       encoder_config->codec_type = PayloadStringToCodecType(payload_name_); | 
 |       encoder_config->video_stream_factory = | 
 |           rtc::make_ref_counted<cricket::EncoderStreamFactory>( | 
 |               payload_name_, /*max_qp=*/56, /*is_screenshare=*/false, | 
 |               /*conference_mode=*/false); | 
 |       encoder_config->max_bitrate_bps = kMaxBitrateBps; | 
 |  | 
 |       if (scalability_mode_.empty()) { | 
 |         for (size_t i = 0; i < num_temporal_layers_.size(); ++i) { | 
 |           VideoStream& stream = encoder_config->simulcast_layers[i]; | 
 |           stream.num_temporal_layers = num_temporal_layers_[i]; | 
 |           configured_num_temporal_layers_[send_config->rtp.ssrcs[i]] = | 
 |               num_temporal_layers_[i]; | 
 |         } | 
 |       } else { | 
 |         for (size_t i = 0; i < scalability_mode_.size(); ++i) { | 
 |           VideoStream& stream = encoder_config->simulcast_layers[i]; | 
 |           stream.scalability_mode = scalability_mode_[i]; | 
 |  | 
 |           configured_num_temporal_layers_[send_config->rtp.ssrcs[i]] = | 
 |               ScalabilityModeToNumTemporalLayers(scalability_mode_[i]); | 
 |         } | 
 |       } | 
 |     } | 
 |  | 
 |     struct ParsedPacket { | 
 |       uint32_t timestamp; | 
 |       uint32_t ssrc; | 
 |       int temporal_idx; | 
 |     }; | 
 |  | 
 |     bool ParsePayload(const uint8_t* packet, | 
 |                       size_t length, | 
 |                       ParsedPacket& parsed) const { | 
 |       RtpPacket rtp_packet; | 
 |       EXPECT_TRUE(rtp_packet.Parse(packet, length)); | 
 |  | 
 |       if (rtp_packet.payload_size() == 0) { | 
 |         return false;  // Padding packet. | 
 |       } | 
 |       parsed.timestamp = rtp_packet.Timestamp(); | 
 |       parsed.ssrc = rtp_packet.Ssrc(); | 
 |  | 
 |       absl::optional<VideoRtpDepacketizer::ParsedRtpPayload> parsed_payload = | 
 |           depacketizer_->Parse(rtp_packet.PayloadBuffer()); | 
 |       EXPECT_TRUE(parsed_payload); | 
 |  | 
 |       if (const auto* vp8_header = absl::get_if<RTPVideoHeaderVP8>( | 
 |               &parsed_payload->video_header.video_type_header)) { | 
 |         parsed.temporal_idx = vp8_header->temporalIdx; | 
 |       } else { | 
 |         RTC_DCHECK_NOTREACHED(); | 
 |       } | 
 |       return true; | 
 |     } | 
 |  | 
 |     Action OnSendRtp(const uint8_t* packet, size_t length) override { | 
 |       ParsedPacket parsed; | 
 |       if (!ParsePayload(packet, length, parsed)) | 
 |         return SEND_PACKET; | 
 |  | 
 |       uint32_t ssrc = parsed.ssrc; | 
 |       int temporal_idx = | 
 |           parsed.temporal_idx == kNoTemporalIdx ? 0 : parsed.temporal_idx; | 
 |       max_observed_tl_idxs_[ssrc] = | 
 |           std::max(temporal_idx, max_observed_tl_idxs_[ssrc]); | 
 |  | 
 |       if (last_observed_packet_.count(ssrc) == 0 || | 
 |           parsed.timestamp != last_observed_packet_[ssrc].timestamp) { | 
 |         num_observed_frames_[ssrc]++; | 
 |       } | 
 |       last_observed_packet_[ssrc] = parsed; | 
 |  | 
 |       if (HighestTemporalLayerSentPerStream()) | 
 |         observation_complete_.Set(); | 
 |  | 
 |       return SEND_PACKET; | 
 |     } | 
 |  | 
 |     bool HighestTemporalLayerSentPerStream() const { | 
 |       if (num_observed_frames_.size() != | 
 |           configured_num_temporal_layers_.size()) { | 
 |         return false; | 
 |       } | 
 |       for (const auto& num_frames : num_observed_frames_) { | 
 |         if (num_frames.second < kMinFramesToObservePerStream) { | 
 |           return false; | 
 |         } | 
 |       } | 
 |       if (max_observed_tl_idxs_.size() != | 
 |           configured_num_temporal_layers_.size()) { | 
 |         return false; | 
 |       } | 
 |       for (const auto& max_tl_idx : max_observed_tl_idxs_) { | 
 |         uint32_t ssrc = max_tl_idx.first; | 
 |         int configured_num_tls = | 
 |             configured_num_temporal_layers_.find(ssrc)->second; | 
 |         if (max_tl_idx.second != configured_num_tls - 1) | 
 |           return false; | 
 |       } | 
 |       return true; | 
 |     } | 
 |  | 
 |     void PerformTest() override { EXPECT_TRUE(Wait()); } | 
 |  | 
 |     VideoEncoderFactory* const encoder_factory_; | 
 |     const std::string payload_name_; | 
 |     const std::vector<int> num_temporal_layers_; | 
 |     const std::vector<ScalabilityMode> scalability_mode_; | 
 |     const std::unique_ptr<VideoRtpDepacketizer> depacketizer_; | 
 |     // Mapped by SSRC. | 
 |     std::map<uint32_t, int> configured_num_temporal_layers_; | 
 |     std::map<uint32_t, int> max_observed_tl_idxs_; | 
 |     std::map<uint32_t, int> num_observed_frames_; | 
 |     std::map<uint32_t, ParsedPacket> last_observed_packet_; | 
 |   } test(encoder_factory, payload_name, num_temporal_layers, scalability_mode); | 
 |  | 
 |   RunBaseTest(&test); | 
 | } | 
 |  | 
 | TEST_F(VideoSendStreamTest, TestTemporalLayersVp8) { | 
 |   InternalEncoderFactory internal_encoder_factory; | 
 |   test::FunctionVideoEncoderFactory encoder_factory( | 
 |       [&internal_encoder_factory]() { | 
 |         return std::make_unique<SimulcastEncoderAdapter>( | 
 |             &internal_encoder_factory, SdpVideoFormat("VP8")); | 
 |       }); | 
 |  | 
 |   TestTemporalLayers(&encoder_factory, "VP8", | 
 |                      /*num_temporal_layers=*/{2}, | 
 |                      /*scalability_mode=*/{}); | 
 | } | 
 |  | 
 | TEST_F(VideoSendStreamTest, TestTemporalLayersVp8Simulcast) { | 
 |   InternalEncoderFactory internal_encoder_factory; | 
 |   test::FunctionVideoEncoderFactory encoder_factory( | 
 |       [&internal_encoder_factory]() { | 
 |         return std::make_unique<SimulcastEncoderAdapter>( | 
 |             &internal_encoder_factory, SdpVideoFormat("VP8")); | 
 |       }); | 
 |  | 
 |   TestTemporalLayers(&encoder_factory, "VP8", | 
 |                      /*num_temporal_layers=*/{2, 2}, | 
 |                      /*scalability_mode=*/{}); | 
 | } | 
 |  | 
 | TEST_F(VideoSendStreamTest, TestTemporalLayersVp8SimulcastWithDifferentNumTls) { | 
 |   InternalEncoderFactory internal_encoder_factory; | 
 |   test::FunctionVideoEncoderFactory encoder_factory( | 
 |       [&internal_encoder_factory]() { | 
 |         return std::make_unique<SimulcastEncoderAdapter>( | 
 |             &internal_encoder_factory, SdpVideoFormat("VP8")); | 
 |       }); | 
 |  | 
 |   TestTemporalLayers(&encoder_factory, "VP8", | 
 |                      /*num_temporal_layers=*/{3, 1}, | 
 |                      /*scalability_mode=*/{}); | 
 | } | 
 |  | 
 | TEST_F(VideoSendStreamTest, TestTemporalLayersVp8SimulcastWithoutSimAdapter) { | 
 |   test::FunctionVideoEncoderFactory encoder_factory( | 
 |       []() { return VP8Encoder::Create(); }); | 
 |  | 
 |   TestTemporalLayers(&encoder_factory, "VP8", | 
 |                      /*num_temporal_layers=*/{2, 2}, | 
 |                      /*scalability_mode=*/{}); | 
 | } | 
 |  | 
 | TEST_F(VideoSendStreamTest, TestScalabilityModeVp8L1T2) { | 
 |   InternalEncoderFactory internal_encoder_factory; | 
 |   test::FunctionVideoEncoderFactory encoder_factory( | 
 |       [&internal_encoder_factory]() { | 
 |         return std::make_unique<SimulcastEncoderAdapter>( | 
 |             &internal_encoder_factory, SdpVideoFormat("VP8")); | 
 |       }); | 
 |  | 
 |   TestTemporalLayers(&encoder_factory, "VP8", | 
 |                      /*num_temporal_layers=*/{}, {ScalabilityMode::kL1T2}); | 
 | } | 
 |  | 
 | TEST_F(VideoSendStreamTest, TestScalabilityModeVp8Simulcast) { | 
 |   InternalEncoderFactory internal_encoder_factory; | 
 |   test::FunctionVideoEncoderFactory encoder_factory( | 
 |       [&internal_encoder_factory]() { | 
 |         return std::make_unique<SimulcastEncoderAdapter>( | 
 |             &internal_encoder_factory, SdpVideoFormat("VP8")); | 
 |       }); | 
 |  | 
 |   TestTemporalLayers(&encoder_factory, "VP8", | 
 |                      /*num_temporal_layers=*/{}, | 
 |                      {ScalabilityMode::kL1T2, ScalabilityMode::kL1T2}); | 
 | } | 
 |  | 
 | TEST_F(VideoSendStreamTest, TestScalabilityModeVp8SimulcastWithDifferentMode) { | 
 |   InternalEncoderFactory internal_encoder_factory; | 
 |   test::FunctionVideoEncoderFactory encoder_factory( | 
 |       [&internal_encoder_factory]() { | 
 |         return std::make_unique<SimulcastEncoderAdapter>( | 
 |             &internal_encoder_factory, SdpVideoFormat("VP8")); | 
 |       }); | 
 |  | 
 |   TestTemporalLayers(&encoder_factory, "VP8", | 
 |                      /*num_temporal_layers=*/{}, | 
 |                      {ScalabilityMode::kL1T3, ScalabilityMode::kL1T1}); | 
 | } | 
 |  | 
 | TEST_F(VideoSendStreamTest, TestScalabilityModeVp8SimulcastWithoutSimAdapter) { | 
 |   test::FunctionVideoEncoderFactory encoder_factory( | 
 |       []() { return VP8Encoder::Create(); }); | 
 |  | 
 |   TestTemporalLayers(&encoder_factory, "VP8", | 
 |                      /*num_temporal_layers=*/{}, | 
 |                      {ScalabilityMode::kL1T2, ScalabilityMode::kL1T2}); | 
 | } | 
 |  | 
 | }  // namespace webrtc |