| Index: webrtc/video/video_send_stream_tests.cc
 | 
| diff --git a/webrtc/video/video_send_stream_tests.cc b/webrtc/video/video_send_stream_tests.cc
 | 
| index 00aa2a901815cb4b0be6296e55e7ade6dae09364..01267735e073a2e35677d4aef72686caa26f6cf1 100644
 | 
| --- a/webrtc/video/video_send_stream_tests.cc
 | 
| +++ b/webrtc/video/video_send_stream_tests.cc
 | 
| @@ -308,48 +308,55 @@ class FakeReceiveStatistics : public NullReceiveStatistics {
 | 
|    StatisticianMap stats_map_;
 | 
|  };
 | 
|  
 | 
| -class FecObserver : public test::SendTest {
 | 
| +class FecObserver : public test::EndToEndTest {
 | 
|   public:
 | 
| -  explicit FecObserver(bool header_extensions_enabled)
 | 
| -      : SendTest(VideoSendStreamTest::kDefaultTimeoutMs),
 | 
| +  FecObserver(bool header_extensions_enabled,
 | 
| +              bool use_nack,
 | 
| +              bool expect_red,
 | 
| +              const std::string& codec)
 | 
| +      : EndToEndTest(VideoSendStreamTest::kDefaultTimeoutMs),
 | 
| +        payload_name_(codec),
 | 
| +        use_nack_(use_nack),
 | 
| +        expect_red_(expect_red),
 | 
|          send_count_(0),
 | 
|          received_media_(false),
 | 
|          received_fec_(false),
 | 
| -        header_extensions_enabled_(header_extensions_enabled) {}
 | 
| +        header_extensions_enabled_(header_extensions_enabled) {
 | 
| +    if (codec == "H264") {
 | 
| +      encoder_.reset(new test::FakeH264Encoder(Clock::GetRealTimeClock()));
 | 
| +    } else if (codec == "VP8") {
 | 
| +      encoder_.reset(VideoEncoder::Create(VideoEncoder::EncoderType::kVp8));
 | 
| +    } else if (codec == "VP9") {
 | 
| +      encoder_.reset(VideoEncoder::Create(VideoEncoder::EncoderType::kVp9));
 | 
| +    } else {
 | 
| +      RTC_NOTREACHED();
 | 
| +    }
 | 
| +  }
 | 
|  
 | 
|   private:
 | 
|    Action OnSendRtp(const uint8_t* packet, size_t length) override {
 | 
|      RTPHeader header;
 | 
|      EXPECT_TRUE(parser_->Parse(packet, length, &header));
 | 
|  
 | 
| -    // Send lossy receive reports to trigger FEC enabling.
 | 
| -    if (send_count_++ % 2 != 0) {
 | 
| -      // Receive statistics reporting having lost 50% of the packets.
 | 
| -      FakeReceiveStatistics lossy_receive_stats(
 | 
| -          VideoSendStreamTest::kVideoSendSsrcs[0], header.sequenceNumber,
 | 
| -          send_count_ / 2, 127);
 | 
| -      RTCPSender rtcp_sender(false, Clock::GetRealTimeClock(),
 | 
| -                             &lossy_receive_stats, nullptr, nullptr,
 | 
| -                             transport_adapter_.get());
 | 
| -
 | 
| -      rtcp_sender.SetRTCPStatus(RtcpMode::kReducedSize);
 | 
| -      rtcp_sender.SetRemoteSSRC(VideoSendStreamTest::kVideoSendSsrcs[0]);
 | 
| -
 | 
| -      RTCPSender::FeedbackState feedback_state;
 | 
| -
 | 
| -      EXPECT_EQ(0, rtcp_sender.SendRTCP(feedback_state, kRtcpRr));
 | 
| -    }
 | 
| -
 | 
| +    ++send_count_;
 | 
|      int encapsulated_payload_type = -1;
 | 
|      if (header.payloadType == VideoSendStreamTest::kRedPayloadType) {
 | 
| +      EXPECT_TRUE(expect_red_);
 | 
|        encapsulated_payload_type = static_cast<int>(packet[header.headerLength]);
 | 
|        if (encapsulated_payload_type !=
 | 
| -          VideoSendStreamTest::kFakeVideoSendPayloadType)
 | 
| +          VideoSendStreamTest::kFakeVideoSendPayloadType) {
 | 
|          EXPECT_EQ(VideoSendStreamTest::kUlpfecPayloadType,
 | 
|                    encapsulated_payload_type);
 | 
| +      }
 | 
|      } else {
 | 
|        EXPECT_EQ(VideoSendStreamTest::kFakeVideoSendPayloadType,
 | 
|                  header.payloadType);
 | 
| +      if (static_cast<size_t>(header.headerLength + header.paddingLength) <
 | 
| +          length) {
 | 
| +        // Not padding-only, media received outside of RED.
 | 
| +        EXPECT_FALSE(expect_red_);
 | 
| +        received_media_ = true;
 | 
| +      }
 | 
|      }
 | 
|  
 | 
|      if (header_extensions_enabled_) {
 | 
| @@ -379,14 +386,27 @@ class FecObserver : public test::SendTest {
 | 
|        }
 | 
|      }
 | 
|  
 | 
| -    if (received_media_ && received_fec_ && send_count_ > 100)
 | 
| -      observation_complete_.Set();
 | 
| +    if (send_count_ > 100 && received_media_) {
 | 
| +      if (received_fec_ || !expect_red_)
 | 
| +        observation_complete_.Set();
 | 
| +    }
 | 
|  
 | 
|      prev_header_ = header;
 | 
|  
 | 
|      return SEND_PACKET;
 | 
|    }
 | 
|  
 | 
| +  test::PacketTransport* CreateSendTransport(Call* sender_call) override {
 | 
| +    // At low RTT (< kLowRttNackMs) -> NACK only, no FEC.
 | 
| +    // Configure some network delay.
 | 
| +    const int kNetworkDelayMs = 100;
 | 
| +    FakeNetworkPipe::Config config;
 | 
| +    config.loss_percent = 50;
 | 
| +    config.queue_delay_ms = kNetworkDelayMs;
 | 
| +    return new test::PacketTransport(sender_call, this,
 | 
| +                                     test::PacketTransport::kSender, config);
 | 
| +  }
 | 
| +
 | 
|    void ModifyVideoConfigs(
 | 
|        VideoSendStream::Config* send_config,
 | 
|        std::vector<VideoReceiveStream::Config>* receive_configs,
 | 
| @@ -394,10 +414,17 @@ class FecObserver : public test::SendTest {
 | 
|      transport_adapter_.reset(
 | 
|          new internal::TransportAdapter(send_config->send_transport));
 | 
|      transport_adapter_->Enable();
 | 
| +    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 = encoder_.get();
 | 
| +    send_config->encoder_settings.payload_name = payload_name_;
 | 
|      send_config->rtp.fec.red_payload_type =
 | 
| -        VideoSendStreamTest::kRedPayloadType;
 | 
| +            VideoSendStreamTest::kRedPayloadType;
 | 
|      send_config->rtp.fec.ulpfec_payload_type =
 | 
| -        VideoSendStreamTest::kUlpfecPayloadType;
 | 
| +            VideoSendStreamTest::kUlpfecPayloadType;
 | 
|      if (header_extensions_enabled_) {
 | 
|        send_config->rtp.extensions.push_back(RtpExtension(
 | 
|            RtpExtension::kAbsSendTime, test::kAbsSendTimeExtensionId));
 | 
| @@ -405,6 +432,10 @@ class FecObserver : public test::SendTest {
 | 
|            RtpExtension(RtpExtension::kTransportSequenceNumber,
 | 
|                         test::kTransportSequenceNumberExtensionId));
 | 
|      }
 | 
| +    (*receive_configs)[0].rtp.fec.red_payload_type =
 | 
| +        send_config->rtp.fec.red_payload_type;
 | 
| +    (*receive_configs)[0].rtp.fec.ulpfec_payload_type =
 | 
| +        send_config->rtp.fec.ulpfec_payload_type;
 | 
|    }
 | 
|  
 | 
|    void PerformTest() override {
 | 
| @@ -412,6 +443,10 @@ class FecObserver : public test::SendTest {
 | 
|    }
 | 
|  
 | 
|    rtc::scoped_ptr<internal::TransportAdapter> transport_adapter_;
 | 
| +  rtc::scoped_ptr<VideoEncoder> encoder_;
 | 
| +  const std::string payload_name_;
 | 
| +  const bool use_nack_;
 | 
| +  const bool expect_red_;
 | 
|    int send_count_;
 | 
|    bool received_media_;
 | 
|    bool received_fec_;
 | 
| @@ -420,14 +455,37 @@ class FecObserver : public test::SendTest {
 | 
|  };
 | 
|  
 | 
|  TEST_F(VideoSendStreamTest, SupportsFecWithExtensions) {
 | 
| -  FecObserver test(true);
 | 
| -
 | 
| +  FecObserver test(true, false, true, "VP8");
 | 
|    RunBaseTest(&test);
 | 
|  }
 | 
|  
 | 
|  TEST_F(VideoSendStreamTest, SupportsFecWithoutExtensions) {
 | 
| -  FecObserver test(false);
 | 
| +  FecObserver test(false, false, true, "VP8");
 | 
| +  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, DoesNotUtilizeRedForH264WithNackEnabled) {
 | 
| +  FecObserver test(false, true, false, "H264");
 | 
| +  RunBaseTest(&test);
 | 
| +}
 | 
| +
 | 
| +// Without retransmissions FEC for H264 is fine.
 | 
| +TEST_F(VideoSendStreamTest, DoesUtilizeRedForH264WithoutNackEnabled) {
 | 
| +  FecObserver test(false, false, true, "H264");
 | 
| +  RunBaseTest(&test);
 | 
| +}
 | 
| +
 | 
| +TEST_F(VideoSendStreamTest, DoesUtilizeRedForVp8WithNackEnabled) {
 | 
| +  FecObserver test(false, true, true, "VP8");
 | 
| +  RunBaseTest(&test);
 | 
| +}
 | 
|  
 | 
| +TEST_F(VideoSendStreamTest, DoesUtilizeRedForVp9WithNackEnabled) {
 | 
| +  FecObserver test(false, true, true, "VP9");
 | 
|    RunBaseTest(&test);
 | 
|  }
 | 
|  
 | 
| 
 |