| Index: webrtc/video/end_to_end_tests.cc
|
| diff --git a/webrtc/video/end_to_end_tests.cc b/webrtc/video/end_to_end_tests.cc
|
| index 3324bbf5f636f1ab66d8e06e4b09ae16d59b1111..c4a0ba27cdab4e7e1e43476e1e3e80849e6abc41 100644
|
| --- a/webrtc/video/end_to_end_tests.cc
|
| +++ b/webrtc/video/end_to_end_tests.cc
|
| @@ -4145,6 +4145,165 @@ TEST_F(EndToEndTest, MAYBE_PictureIdStateRetainedAfterReinitingVp8) {
|
| TestPictureIdStatePreservation(encoder.get());
|
| }
|
|
|
| +TEST_F(EndToEndTest, TestFlexfecRtpStatePreservation) {
|
| + class RtpSequenceObserver : public test::RtpRtcpObserver {
|
| + public:
|
| + RtpSequenceObserver()
|
| + : test::RtpRtcpObserver(kDefaultTimeoutMs),
|
| + num_flexfec_packets_sent_(0) {}
|
| +
|
| + void ResetPacketCount() {
|
| + rtc::CritScope lock(&crit_);
|
| + num_flexfec_packets_sent_ = 0;
|
| + }
|
| +
|
| + private:
|
| + Action OnSendRtp(const uint8_t* packet, size_t length) override {
|
| + rtc::CritScope lock(&crit_);
|
| +
|
| + RTPHeader header;
|
| + EXPECT_TRUE(parser_->Parse(packet, length, &header));
|
| + const uint16_t sequence_number = header.sequenceNumber;
|
| + const uint32_t timestamp = header.timestamp;
|
| + const uint32_t ssrc = header.ssrc;
|
| +
|
| + if (ssrc == kVideoSendSsrcs[0] || ssrc == kSendRtxSsrcs[0]) {
|
| + return SEND_PACKET;
|
| + }
|
| + EXPECT_EQ(kFlexfecSendSsrc, ssrc) << "Unknown SSRC sent.";
|
| +
|
| + ++num_flexfec_packets_sent_;
|
| +
|
| + // If this is the first packet, we have nothing to compare to.
|
| + if (!last_observed_sequence_number_) {
|
| + last_observed_sequence_number_.emplace(sequence_number);
|
| + last_observed_timestamp_.emplace(timestamp);
|
| +
|
| + return SEND_PACKET;
|
| + }
|
| +
|
| + // Verify continuity and monotonicity of RTP sequence numbers.
|
| + EXPECT_EQ(static_cast<uint16_t>(*last_observed_sequence_number_ + 1),
|
| + sequence_number);
|
| + last_observed_sequence_number_.emplace(sequence_number);
|
| +
|
| + // Timestamps should be non-decreasing...
|
| + const bool timestamp_is_same_or_newer =
|
| + timestamp == *last_observed_timestamp_ ||
|
| + IsNewerTimestamp(timestamp, *last_observed_timestamp_);
|
| + EXPECT_TRUE(timestamp_is_same_or_newer);
|
| + // ...but reasonably close in time.
|
| + const int k10SecondsInRtpTimestampBase = 10 * kVideoPayloadTypeFrequency;
|
| + EXPECT_TRUE(IsNewerTimestamp(
|
| + *last_observed_timestamp_ + k10SecondsInRtpTimestampBase, timestamp));
|
| + last_observed_timestamp_.emplace(timestamp);
|
| +
|
| + // Pass test when enough packets have been let through.
|
| + if (num_flexfec_packets_sent_ >= 10) {
|
| + observation_complete_.Set();
|
| + }
|
| +
|
| + return SEND_PACKET;
|
| + }
|
| +
|
| + rtc::Optional<uint16_t> last_observed_sequence_number_ GUARDED_BY(crit_);
|
| + rtc::Optional<uint32_t> last_observed_timestamp_ GUARDED_BY(crit_);
|
| + size_t num_flexfec_packets_sent_ GUARDED_BY(crit_);
|
| + rtc::CriticalSection crit_;
|
| + } observer;
|
| +
|
| + Call::Config config(event_log_.get());
|
| + CreateCalls(config, config);
|
| +
|
| + FakeNetworkPipe::Config lossy_delayed_link;
|
| + lossy_delayed_link.loss_percent = 2;
|
| + lossy_delayed_link.queue_delay_ms = 50;
|
| + test::PacketTransport send_transport(sender_call_.get(), &observer,
|
| + test::PacketTransport::kSender,
|
| + payload_type_map_, lossy_delayed_link);
|
| + send_transport.SetReceiver(receiver_call_->Receiver());
|
| +
|
| + FakeNetworkPipe::Config flawless_link;
|
| + test::PacketTransport receive_transport(nullptr, &observer,
|
| + test::PacketTransport::kReceiver,
|
| + payload_type_map_, flawless_link);
|
| + receive_transport.SetReceiver(sender_call_->Receiver());
|
| +
|
| + // For reduced flakyness, we use a real VP8 encoder together with NACK
|
| + // and RTX.
|
| + const int kNumVideoStreams = 1;
|
| + const int kNumFlexfecStreams = 1;
|
| + CreateSendConfig(kNumVideoStreams, 0, kNumFlexfecStreams, &send_transport);
|
| + std::unique_ptr<VideoEncoder> encoder(VP8Encoder::Create());
|
| + video_send_config_.encoder_settings.encoder = encoder.get();
|
| + video_send_config_.encoder_settings.payload_name = "VP8";
|
| + video_send_config_.encoder_settings.payload_type = kVideoSendPayloadType;
|
| + video_send_config_.rtp.nack.rtp_history_ms = kNackRtpHistoryMs;
|
| + video_send_config_.rtp.rtx.ssrcs.push_back(kSendRtxSsrcs[0]);
|
| + video_send_config_.rtp.rtx.payload_type = kSendRtxPayloadType;
|
| +
|
| + CreateMatchingReceiveConfigs(&receive_transport);
|
| + video_receive_configs_[0].rtp.nack.rtp_history_ms = kNackRtpHistoryMs;
|
| + video_receive_configs_[0].rtp.rtx_ssrc = kSendRtxSsrcs[0];
|
| + video_receive_configs_[0].rtp.rtx_payload_types[kVideoSendPayloadType] =
|
| + kSendRtxPayloadType;
|
| +
|
| + // The matching FlexFEC receive config is not created by
|
| + // CreateMatchingReceiveConfigs since this is not a test::BaseTest.
|
| + // Set up the receive config manually instead.
|
| + FlexfecReceiveStream::Config flexfec_receive_config(&receive_transport);
|
| + flexfec_receive_config.payload_type =
|
| + video_send_config_.rtp.flexfec.payload_type;
|
| + flexfec_receive_config.remote_ssrc = video_send_config_.rtp.flexfec.ssrc;
|
| + flexfec_receive_config.protected_media_ssrcs =
|
| + video_send_config_.rtp.flexfec.protected_media_ssrcs;
|
| + flexfec_receive_config.local_ssrc = kReceiverLocalVideoSsrc;
|
| + flexfec_receive_config.transport_cc = true;
|
| + flexfec_receive_config.rtp_header_extensions.emplace_back(
|
| + RtpExtension::kTransportSequenceNumberUri,
|
| + test::kTransportSequenceNumberExtensionId);
|
| + flexfec_receive_configs_.push_back(flexfec_receive_config);
|
| +
|
| + CreateFlexfecStreams();
|
| + CreateVideoStreams();
|
| +
|
| + // RTCP might be disabled if the network is "down".
|
| + sender_call_->SignalChannelNetworkState(MediaType::VIDEO, kNetworkUp);
|
| + receiver_call_->SignalChannelNetworkState(MediaType::VIDEO, kNetworkUp);
|
| +
|
| + const int kFrameMaxWidth = 320;
|
| + const int kFrameMaxHeight = 180;
|
| + const int kFrameRate = 15;
|
| + CreateFrameGeneratorCapturer(kFrameRate, kFrameMaxWidth, kFrameMaxHeight);
|
| +
|
| + // Initial test.
|
| + Start();
|
| + EXPECT_TRUE(observer.Wait()) << "Timed out waiting for packets.";
|
| +
|
| + // Ensure monotonicity when the VideoSendStream is restarted.
|
| + Stop();
|
| + observer.ResetPacketCount();
|
| + Start();
|
| + EXPECT_TRUE(observer.Wait()) << "Timed out waiting for packets.";
|
| +
|
| + // Ensure monotonicity when the VideoSendStream is recreated.
|
| + frame_generator_capturer_->Stop();
|
| + sender_call_->DestroyVideoSendStream(video_send_stream_);
|
| + observer.ResetPacketCount();
|
| + video_send_stream_ = sender_call_->CreateVideoSendStream(
|
| + video_send_config_.Copy(), video_encoder_config_.Copy());
|
| + video_send_stream_->Start();
|
| + CreateFrameGeneratorCapturer(kFrameRate, kFrameMaxWidth, kFrameMaxHeight);
|
| + frame_generator_capturer_->Start();
|
| + EXPECT_TRUE(observer.Wait()) << "Timed out waiting for packets.";
|
| +
|
| + // Cleanup.
|
| + send_transport.StopSending();
|
| + receive_transport.StopSending();
|
| + Stop();
|
| + DestroyStreams();
|
| +}
|
| +
|
| TEST_F(EndToEndTest,
|
| MAYBE_PictureIdStateRetainedAfterReinitingSimulcastEncoderAdapter) {
|
| class VideoEncoderFactoryAdapter : public webrtc::VideoEncoderFactory {
|
|
|