/*
 *  Copyright 2017 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 "video/video_receive_stream2.h"

#include <algorithm>
#include <cstddef>
#include <deque>
#include <limits>
#include <memory>
#include <ostream>
#include <queue>
#include <tuple>
#include <utility>
#include <vector>

#include "absl/memory/memory.h"
#include "absl/types/optional.h"
#include "api/metronome/test/fake_metronome.h"
#include "api/test/mock_video_decoder.h"
#include "api/test/mock_video_decoder_factory.h"
#include "api/test/time_controller.h"
#include "api/units/frequency.h"
#include "api/units/time_delta.h"
#include "api/video/encoded_image.h"
#include "api/video/recordable_encoded_frame.h"
#include "api/video/test/video_frame_matchers.h"
#include "api/video/video_frame.h"
#include "api/video_codecs/sdp_video_format.h"
#include "api/video_codecs/video_decoder.h"
#include "call/rtp_stream_receiver_controller.h"
#include "call/video_receive_stream.h"
#include "common_video/test/utilities.h"
#include "media/engine/fake_webrtc_call.h"
#include "modules/pacing/packet_router.h"
#include "modules/rtp_rtcp/source/rtp_packet_to_send.h"
#include "modules/video_coding/encoded_frame.h"
#include "rtc_base/logging.h"
#include "system_wrappers/include/clock.h"
#include "test/fake_decoder.h"
#include "test/fake_encoded_frame.h"
#include "test/gmock.h"
#include "test/gtest.h"
#include "test/mock_transport.h"
#include "test/rtcp_packet_parser.h"
#include "test/time_controller/simulated_time_controller.h"
#include "test/video_decoder_proxy_factory.h"
#include "video/call_stats2.h"

namespace webrtc {

// Printing SdpVideoFormat for gmock argument matchers.
void PrintTo(const SdpVideoFormat& value, std::ostream* os) {
  *os << value.ToString();
}

void PrintTo(const RecordableEncodedFrame::EncodedResolution& value,
             std::ostream* os) {
  *os << value.width << "x" << value.height;
}

void PrintTo(const RecordableEncodedFrame& value, std::ostream* os) {
  *os << "RecordableEncodedFrame(render_time=" << value.render_time()
      << " resolution=" << ::testing::PrintToString(value.resolution()) << ")";
}

}  // namespace webrtc

namespace webrtc {

namespace {

using test::video_frame_matchers::NtpTimestamp;
using test::video_frame_matchers::PacketInfos;
using test::video_frame_matchers::Rotation;
using ::testing::_;
using ::testing::AllOf;
using ::testing::AnyNumber;
using ::testing::ElementsAreArray;
using ::testing::Eq;
using ::testing::Field;
using ::testing::InSequence;
using ::testing::Invoke;
using ::testing::IsEmpty;
using ::testing::Optional;
using ::testing::Pointee;
using ::testing::Property;
using ::testing::Return;
using ::testing::SizeIs;
using ::testing::WithoutArgs;

auto RenderedFrameWith(::testing::Matcher<VideoFrame> m) {
  return Optional(m);
}
auto RenderedFrame() {
  return RenderedFrameWith(_);
}
testing::Matcher<absl::optional<VideoFrame>> DidNotReceiveFrame() {
  return Eq(absl::nullopt);
}

constexpr TimeDelta kDefaultTimeOut = TimeDelta::Millis(50);
constexpr int kDefaultNumCpuCores = 2;

constexpr Timestamp kStartTime = Timestamp::Millis(1'337'000);
constexpr Frequency k30Fps = Frequency::Hertz(30);
constexpr TimeDelta k30FpsDelay = 1 / k30Fps;
constexpr Frequency kRtpTimestampHz = Frequency::KiloHertz(90);
constexpr uint32_t k30FpsRtpTimestampDelta = kRtpTimestampHz / k30Fps;
constexpr uint32_t kFirstRtpTimestamp = 90000;

class FakeVideoRenderer : public rtc::VideoSinkInterface<VideoFrame> {
 public:
  explicit FakeVideoRenderer(TimeController* time_controller)
      : time_controller_(time_controller) {}
  ~FakeVideoRenderer() override = default;

  void OnFrame(const VideoFrame& frame) override {
    RTC_LOG(LS_VERBOSE) << "Received frame with timestamp="
                        << frame.timestamp();
    if (!last_frame_.empty()) {
      RTC_LOG(LS_INFO) << "Already had frame queue with timestamp="
                       << last_frame_.back().timestamp();
    }
    last_frame_.push_back(frame);
  }

  // If `advance_time`, then the clock will always advance by `timeout`.
  absl::optional<VideoFrame> WaitForFrame(TimeDelta timeout,
                                          bool advance_time = false) {
    auto start = time_controller_->GetClock()->CurrentTime();
    if (last_frame_.empty()) {
      time_controller_->AdvanceTime(TimeDelta::Zero());
      time_controller_->Wait([this] { return !last_frame_.empty(); }, timeout);
    }
    absl::optional<VideoFrame> ret;
    if (!last_frame_.empty()) {
      ret = last_frame_.front();
      last_frame_.pop_front();
    }
    if (advance_time) {
      time_controller_->AdvanceTime(
          timeout - (time_controller_->GetClock()->CurrentTime() - start));
    }
    return ret;
  }

 private:
  std::deque<VideoFrame> last_frame_;
  TimeController* const time_controller_;
};

MATCHER_P2(MatchResolution, w, h, "") {
  return arg.resolution().width == w && arg.resolution().height == h;
}

MATCHER_P(RtpTimestamp, timestamp, "") {
  if (arg.timestamp() != timestamp) {
    *result_listener->stream()
        << "rtp timestamp was " << arg.timestamp() << " != " << timestamp;
    return false;
  }
  return true;
}

// Rtp timestamp for in order frame at 30fps.
uint32_t RtpTimestampForFrame(int id) {
  return kFirstRtpTimestamp + id * k30FpsRtpTimestampDelta;
}

// Receive time for in order frame at 30fps.
Timestamp ReceiveTimeForFrame(int id) {
  return kStartTime + id * k30FpsDelay;
}

}  // namespace

class VideoReceiveStream2Test : public ::testing::TestWithParam<bool> {
 public:
  auto DefaultDecodeAction() {
    return Invoke(&fake_decoder_, &test::FakeDecoder::Decode);
  }

  bool UseMetronome() const { return GetParam(); }

  VideoReceiveStream2Test()
      : time_controller_(kStartTime),
        clock_(time_controller_.GetClock()),
        config_(&mock_transport_, &mock_h264_decoder_factory_),
        call_stats_(clock_, time_controller_.GetMainThread()),
        fake_renderer_(&time_controller_),
        fake_metronome_(TimeDelta::Millis(16)),
        decode_sync_(clock_,
                     &fake_metronome_,
                     time_controller_.GetMainThread()),
        h264_decoder_factory_(&mock_decoder_) {
    // By default, mock decoder factory is backed by VideoDecoderProxyFactory.
    ON_CALL(mock_h264_decoder_factory_, CreateVideoDecoder)
        .WillByDefault(
            Invoke(&h264_decoder_factory_,
                   &test::VideoDecoderProxyFactory::CreateVideoDecoder));

    // By default, mock decode will wrap the fake decoder.
    ON_CALL(mock_decoder_, Configure)
        .WillByDefault(Invoke(&fake_decoder_, &test::FakeDecoder::Configure));
    ON_CALL(mock_decoder_, Decode).WillByDefault(DefaultDecodeAction());
    ON_CALL(mock_decoder_, RegisterDecodeCompleteCallback)
        .WillByDefault(
            Invoke(&fake_decoder_,
                   &test::FakeDecoder::RegisterDecodeCompleteCallback));
    ON_CALL(mock_decoder_, Release)
        .WillByDefault(Invoke(&fake_decoder_, &test::FakeDecoder::Release));
    ON_CALL(mock_transport_, SendRtcp)
        .WillByDefault(
            Invoke(&rtcp_packet_parser_, &test::RtcpPacketParser::Parse));
  }

  ~VideoReceiveStream2Test() override {
    if (video_receive_stream_) {
      video_receive_stream_->Stop();
      video_receive_stream_->UnregisterFromTransport();
    }
    time_controller_.AdvanceTime(TimeDelta::Zero());
  }

  void SetUp() override {
    config_.rtp.remote_ssrc = 1111;
    config_.rtp.local_ssrc = 2222;
    config_.renderer = &fake_renderer_;
    VideoReceiveStreamInterface::Decoder h264_decoder;
    h264_decoder.payload_type = 99;
    h264_decoder.video_format = SdpVideoFormat("H264");
    h264_decoder.video_format.parameters.insert(
        {"sprop-parameter-sets", "Z0IACpZTBYmI,aMljiA=="});
    VideoReceiveStreamInterface::Decoder h265_decoder;
    h265_decoder.payload_type = 100;
    h265_decoder.video_format = SdpVideoFormat("H265");

    config_.decoders = {h265_decoder, h264_decoder};

    RecreateReceiveStream();
  }

  void RecreateReceiveStream(
      absl::optional<VideoReceiveStreamInterface::RecordingState> state =
          absl::nullopt) {
    if (video_receive_stream_) {
      video_receive_stream_->UnregisterFromTransport();
      video_receive_stream_ = nullptr;
    }
    timing_ = new VCMTiming(clock_, fake_call_.trials());
    video_receive_stream_ =
        std::make_unique<webrtc::internal::VideoReceiveStream2>(
            time_controller_.GetTaskQueueFactory(), &fake_call_,
            kDefaultNumCpuCores, &packet_router_, config_.Copy(), &call_stats_,
            clock_, absl::WrapUnique(timing_), &nack_periodic_processor_,
            UseMetronome() ? &decode_sync_ : nullptr, nullptr);
    video_receive_stream_->RegisterWithTransport(
        &rtp_stream_receiver_controller_);
    if (state)
      video_receive_stream_->SetAndGetRecordingState(std::move(*state), false);
  }

 protected:
  GlobalSimulatedTimeController time_controller_;
  Clock* const clock_;
  NackPeriodicProcessor nack_periodic_processor_;
  testing::NiceMock<MockVideoDecoderFactory> mock_h264_decoder_factory_;
  VideoReceiveStreamInterface::Config config_;
  internal::CallStats call_stats_;
  testing::NiceMock<MockVideoDecoder> mock_decoder_;
  FakeVideoRenderer fake_renderer_;
  cricket::FakeCall fake_call_;
  MockTransport mock_transport_;
  test::RtcpPacketParser rtcp_packet_parser_;
  PacketRouter packet_router_;
  RtpStreamReceiverController rtp_stream_receiver_controller_;
  std::unique_ptr<webrtc::internal::VideoReceiveStream2> video_receive_stream_;
  VCMTiming* timing_;
  test::FakeMetronome fake_metronome_;
  DecodeSynchronizer decode_sync_;

 private:
  test::VideoDecoderProxyFactory h264_decoder_factory_;
  test::FakeDecoder fake_decoder_;
};

TEST_P(VideoReceiveStream2Test, CreateFrameFromH264FmtpSpropAndIdr) {
  constexpr uint8_t idr_nalu[] = {0x05, 0xFF, 0xFF, 0xFF};
  RtpPacketToSend rtppacket(nullptr);
  uint8_t* payload = rtppacket.AllocatePayload(sizeof(idr_nalu));
  memcpy(payload, idr_nalu, sizeof(idr_nalu));
  rtppacket.SetMarker(true);
  rtppacket.SetSsrc(1111);
  rtppacket.SetPayloadType(99);
  rtppacket.SetSequenceNumber(1);
  rtppacket.SetTimestamp(0);
  EXPECT_CALL(mock_decoder_, RegisterDecodeCompleteCallback(_));
  video_receive_stream_->Start();
  EXPECT_CALL(mock_decoder_, Decode(_, false, _));
  RtpPacketReceived parsed_packet;
  ASSERT_TRUE(parsed_packet.Parse(rtppacket.data(), rtppacket.size()));
  rtp_stream_receiver_controller_.OnRtpPacket(parsed_packet);
  EXPECT_CALL(mock_decoder_, Release());

  time_controller_.AdvanceTime(TimeDelta::Zero());
}

TEST_P(VideoReceiveStream2Test, PlayoutDelay) {
  const VideoPlayoutDelay kPlayoutDelayMs = {123, 321};
  std::unique_ptr<test::FakeEncodedFrame> test_frame =
      test::FakeFrameBuilder().Id(0).AsLast().Build();
  test_frame->SetPlayoutDelay(kPlayoutDelayMs);

  video_receive_stream_->OnCompleteFrame(std::move(test_frame));
  auto timings = timing_->GetTimings();
  EXPECT_EQ(kPlayoutDelayMs.min_ms, timings.min_playout_delay.ms());
  EXPECT_EQ(kPlayoutDelayMs.max_ms, timings.max_playout_delay.ms());

  // Check that the biggest minimum delay is chosen.
  video_receive_stream_->SetMinimumPlayoutDelay(400);
  timings = timing_->GetTimings();
  EXPECT_EQ(400, timings.min_playout_delay.ms());

  // Check base minimum delay validation.
  EXPECT_FALSE(video_receive_stream_->SetBaseMinimumPlayoutDelayMs(12345));
  EXPECT_FALSE(video_receive_stream_->SetBaseMinimumPlayoutDelayMs(-1));
  EXPECT_TRUE(video_receive_stream_->SetBaseMinimumPlayoutDelayMs(500));
  timings = timing_->GetTimings();
  EXPECT_EQ(500, timings.min_playout_delay.ms());

  // Check that intermidiate values are remembered and the biggest remembered
  // is chosen.
  video_receive_stream_->SetBaseMinimumPlayoutDelayMs(0);
  timings = timing_->GetTimings();
  EXPECT_EQ(400, timings.min_playout_delay.ms());

  video_receive_stream_->SetMinimumPlayoutDelay(0);
  timings = timing_->GetTimings();
  EXPECT_EQ(123, timings.min_playout_delay.ms());
}

TEST_P(VideoReceiveStream2Test, PlayoutDelayPreservesDefaultMaxValue) {
  const TimeDelta default_max_playout_latency =
      timing_->GetTimings().max_playout_delay;
  const VideoPlayoutDelay kPlayoutDelayMs = {123, -1};

  std::unique_ptr<test::FakeEncodedFrame> test_frame =
      test::FakeFrameBuilder().Id(0).AsLast().Build();
  test_frame->SetPlayoutDelay(kPlayoutDelayMs);

  video_receive_stream_->OnCompleteFrame(std::move(test_frame));

  // Ensure that -1 preserves default maximum value from `timing_`.
  auto timings = timing_->GetTimings();
  EXPECT_EQ(kPlayoutDelayMs.min_ms, timings.min_playout_delay.ms());
  EXPECT_NE(kPlayoutDelayMs.max_ms, timings.max_playout_delay.ms());
  EXPECT_EQ(default_max_playout_latency, timings.max_playout_delay);
}

TEST_P(VideoReceiveStream2Test, PlayoutDelayPreservesDefaultMinValue) {
  const TimeDelta default_min_playout_latency =
      timing_->GetTimings().min_playout_delay;
  const VideoPlayoutDelay kPlayoutDelayMs = {-1, 321};

  std::unique_ptr<test::FakeEncodedFrame> test_frame =
      test::FakeFrameBuilder().Id(0).AsLast().Build();
  test_frame->SetPlayoutDelay(kPlayoutDelayMs);

  video_receive_stream_->OnCompleteFrame(std::move(test_frame));

  // Ensure that -1 preserves default minimum value from `timing_`.
  auto timings = timing_->GetTimings();
  EXPECT_NE(kPlayoutDelayMs.min_ms, timings.min_playout_delay.ms());
  EXPECT_EQ(kPlayoutDelayMs.max_ms, timings.max_playout_delay.ms());
  EXPECT_EQ(default_min_playout_latency, timings.min_playout_delay);
}

TEST_P(VideoReceiveStream2Test, RenderParametersSetToDefaultValues) {
  // Default render parameters.
  const VideoFrame::RenderParameters kDefaultRenderParameters;
  // Default with no playout delay set.
  std::unique_ptr<test::FakeEncodedFrame> test_frame0 =
      test::FakeFrameBuilder().Id(0).AsLast().Build();
  video_receive_stream_->OnCompleteFrame(std::move(test_frame0));
  EXPECT_EQ(timing_->RenderParameters(), kDefaultRenderParameters);
}

TEST_P(VideoReceiveStream2Test, UseLowLatencyRenderingSetFromPlayoutDelay) {
  // use_low_latency_rendering set if playout delay set to min=0, max<=500 ms.
  std::unique_ptr<test::FakeEncodedFrame> test_frame0 =
      test::FakeFrameBuilder().Id(0).AsLast().Build();
  test_frame0->SetPlayoutDelay({/*min_ms=*/0, /*max_ms=*/0});
  video_receive_stream_->OnCompleteFrame(std::move(test_frame0));
  EXPECT_TRUE(timing_->RenderParameters().use_low_latency_rendering);

  std::unique_ptr<test::FakeEncodedFrame> test_frame1 =
      test::FakeFrameBuilder().Id(1).AsLast().Build();
  test_frame1->SetPlayoutDelay({/*min_ms=*/0, /*max_ms=*/500});
  video_receive_stream_->OnCompleteFrame(std::move(test_frame1));
  EXPECT_TRUE(timing_->RenderParameters().use_low_latency_rendering);
}

TEST_P(VideoReceiveStream2Test, MaxCompositionDelaySetFromMaxPlayoutDelay) {
  // The max composition delay is dependent on the number of frames in the
  // pre-decode queue. It's therefore important to advance the time as the test
  // runs to get the correct expectations of max_composition_delay_in_frames.
  video_receive_stream_->Start();
  // Max composition delay not set if no playout delay is set.
  std::unique_ptr<test::FakeEncodedFrame> test_frame0 =
      test::FakeFrameBuilder()
          .Id(0)
          .Time(RtpTimestampForFrame(0))
          .ReceivedTime(ReceiveTimeForFrame(0))
          .AsLast()
          .Build();
  video_receive_stream_->OnCompleteFrame(std::move(test_frame0));
  EXPECT_THAT(timing_->RenderParameters().max_composition_delay_in_frames,
              Eq(absl::nullopt));
  time_controller_.AdvanceTime(k30FpsDelay);

  // Max composition delay not set for playout delay 0,0.
  std::unique_ptr<test::FakeEncodedFrame> test_frame1 =
      test::FakeFrameBuilder()
          .Id(1)
          .Time(RtpTimestampForFrame(1))
          .ReceivedTime(ReceiveTimeForFrame(1))
          .AsLast()
          .Build();
  test_frame1->SetPlayoutDelay({0, 0});
  video_receive_stream_->OnCompleteFrame(std::move(test_frame1));
  EXPECT_THAT(timing_->RenderParameters().max_composition_delay_in_frames,
              Eq(absl::nullopt));
  time_controller_.AdvanceTime(k30FpsDelay);

  // Max composition delay not set for playout delay X,Y, where X,Y>0.
  std::unique_ptr<test::FakeEncodedFrame> test_frame2 =
      test::FakeFrameBuilder()
          .Id(2)
          .Time(RtpTimestampForFrame(2))
          .ReceivedTime(ReceiveTimeForFrame(2))
          .AsLast()
          .Build();
  test_frame2->SetPlayoutDelay({10, 30});
  video_receive_stream_->OnCompleteFrame(std::move(test_frame2));
  EXPECT_THAT(timing_->RenderParameters().max_composition_delay_in_frames,
              Eq(absl::nullopt));

  time_controller_.AdvanceTime(k30FpsDelay);

  // Max composition delay set if playout delay X,Y, where X=0,Y>0.
  const int kExpectedMaxCompositionDelayInFrames = 3;  // ~50 ms at 60 fps.
  std::unique_ptr<test::FakeEncodedFrame> test_frame3 =
      test::FakeFrameBuilder()
          .Id(3)
          .Time(RtpTimestampForFrame(3))
          .ReceivedTime(ReceiveTimeForFrame(3))
          .AsLast()
          .Build();
  test_frame3->SetPlayoutDelay({0, 50});
  video_receive_stream_->OnCompleteFrame(std::move(test_frame3));
  EXPECT_THAT(timing_->RenderParameters().max_composition_delay_in_frames,
              Optional(kExpectedMaxCompositionDelayInFrames));
}

TEST_P(VideoReceiveStream2Test, LazyDecoderCreation) {
  constexpr uint8_t idr_nalu[] = {0x05, 0xFF, 0xFF, 0xFF};
  RtpPacketToSend rtppacket(nullptr);
  uint8_t* payload = rtppacket.AllocatePayload(sizeof(idr_nalu));
  memcpy(payload, idr_nalu, sizeof(idr_nalu));
  rtppacket.SetMarker(true);
  rtppacket.SetSsrc(1111);
  // H265 payload type.
  rtppacket.SetPayloadType(99);
  rtppacket.SetSequenceNumber(1);
  rtppacket.SetTimestamp(0);

  // No decoders are created by default.
  EXPECT_CALL(mock_h264_decoder_factory_, CreateVideoDecoder(_)).Times(0);
  video_receive_stream_->Start();
  time_controller_.AdvanceTime(TimeDelta::Zero());

  EXPECT_TRUE(
      testing::Mock::VerifyAndClearExpectations(&mock_h264_decoder_factory_));
  // Verify that the decoder is created when we receive payload data and tries
  // to decode a frame.
  EXPECT_CALL(
      mock_h264_decoder_factory_,
      CreateVideoDecoder(Field(&SdpVideoFormat::name, testing::Eq("H264"))));
  EXPECT_CALL(mock_decoder_, Configure);
  EXPECT_CALL(mock_decoder_, RegisterDecodeCompleteCallback);
  EXPECT_CALL(mock_decoder_, Decode);
  RtpPacketReceived parsed_packet;
  ASSERT_TRUE(parsed_packet.Parse(rtppacket.data(), rtppacket.size()));
  rtp_stream_receiver_controller_.OnRtpPacket(parsed_packet);
  EXPECT_CALL(mock_decoder_, Release);

  // Make sure the decoder thread had a chance to run.
  time_controller_.AdvanceTime(TimeDelta::Zero());
}

TEST_P(VideoReceiveStream2Test, PassesNtpTime) {
  const Timestamp kNtpTimestamp = Timestamp::Millis(12345);
  std::unique_ptr<test::FakeEncodedFrame> test_frame =
      test::FakeFrameBuilder()
          .Id(0)
          .PayloadType(99)
          .NtpTime(kNtpTimestamp)
          .AsLast()
          .Build();

  video_receive_stream_->Start();
  video_receive_stream_->OnCompleteFrame(std::move(test_frame));
  EXPECT_THAT(fake_renderer_.WaitForFrame(kDefaultTimeOut),
              RenderedFrameWith(NtpTimestamp(kNtpTimestamp)));
}

TEST_P(VideoReceiveStream2Test, PassesRotation) {
  const webrtc::VideoRotation kRotation = webrtc::kVideoRotation_180;
  std::unique_ptr<test::FakeEncodedFrame> test_frame = test::FakeFrameBuilder()
                                                           .Id(0)
                                                           .PayloadType(99)
                                                           .Rotation(kRotation)
                                                           .AsLast()
                                                           .Build();

  video_receive_stream_->Start();
  video_receive_stream_->OnCompleteFrame(std::move(test_frame));
  EXPECT_THAT(fake_renderer_.WaitForFrame(kDefaultTimeOut),
              RenderedFrameWith(Rotation(kRotation)));
}

TEST_P(VideoReceiveStream2Test, PassesPacketInfos) {
  RtpPacketInfos packet_infos = CreatePacketInfos(3);
  auto test_frame = test::FakeFrameBuilder()
                        .Id(0)
                        .PayloadType(99)
                        .PacketInfos(packet_infos)
                        .AsLast()
                        .Build();

  video_receive_stream_->Start();
  video_receive_stream_->OnCompleteFrame(std::move(test_frame));
  EXPECT_THAT(fake_renderer_.WaitForFrame(kDefaultTimeOut),
              RenderedFrameWith(PacketInfos(ElementsAreArray(packet_infos))));
}

TEST_P(VideoReceiveStream2Test, RenderedFrameUpdatesGetSources) {
  constexpr uint32_t kSsrc = 1111;
  constexpr uint32_t kCsrc = 9001;
  constexpr uint32_t kRtpTimestamp = 12345;

  // Prepare one video frame with per-packet information.
  auto test_frame =
      test::FakeFrameBuilder().Id(0).PayloadType(99).AsLast().Build();
  RtpPacketInfos packet_infos;
  {
    RtpPacketInfos::vector_type infos;

    RtpPacketInfo info;
    info.set_ssrc(kSsrc);
    info.set_csrcs({kCsrc});
    info.set_rtp_timestamp(kRtpTimestamp);

    info.set_receive_time(clock_->CurrentTime() - TimeDelta::Millis(5000));
    infos.push_back(info);

    info.set_receive_time(clock_->CurrentTime() - TimeDelta::Millis(3000));
    infos.push_back(info);

    info.set_receive_time(clock_->CurrentTime() - TimeDelta::Millis(2000));
    infos.push_back(info);

    info.set_receive_time(clock_->CurrentTime() - TimeDelta::Millis(1000));
    infos.push_back(info);

    packet_infos = RtpPacketInfos(std::move(infos));
  }
  test_frame->SetPacketInfos(packet_infos);

  // Start receive stream.
  video_receive_stream_->Start();
  EXPECT_THAT(video_receive_stream_->GetSources(), IsEmpty());

  // Render one video frame.
  int64_t timestamp_ms_min = clock_->TimeInMilliseconds();
  video_receive_stream_->OnCompleteFrame(std::move(test_frame));
  // Verify that the per-packet information is passed to the renderer.
  EXPECT_THAT(fake_renderer_.WaitForFrame(kDefaultTimeOut),
              RenderedFrameWith(PacketInfos(ElementsAreArray(packet_infos))));
  int64_t timestamp_ms_max = clock_->TimeInMilliseconds();

  // Verify that the per-packet information also updates `GetSources()`.
  std::vector<RtpSource> sources = video_receive_stream_->GetSources();
  ASSERT_THAT(sources, SizeIs(2));
  {
    auto it = std::find_if(sources.begin(), sources.end(),
                           [](const RtpSource& source) {
                             return source.source_type() == RtpSourceType::SSRC;
                           });
    ASSERT_NE(it, sources.end());

    EXPECT_EQ(it->source_id(), kSsrc);
    EXPECT_EQ(it->source_type(), RtpSourceType::SSRC);
    EXPECT_EQ(it->rtp_timestamp(), kRtpTimestamp);
    EXPECT_GE(it->timestamp_ms(), timestamp_ms_min);
    EXPECT_LE(it->timestamp_ms(), timestamp_ms_max);
  }
  {
    auto it = std::find_if(sources.begin(), sources.end(),
                           [](const RtpSource& source) {
                             return source.source_type() == RtpSourceType::CSRC;
                           });
    ASSERT_NE(it, sources.end());

    EXPECT_EQ(it->source_id(), kCsrc);
    EXPECT_EQ(it->source_type(), RtpSourceType::CSRC);
    EXPECT_EQ(it->rtp_timestamp(), kRtpTimestamp);
    EXPECT_GE(it->timestamp_ms(), timestamp_ms_min);
    EXPECT_LE(it->timestamp_ms(), timestamp_ms_max);
  }
}

std::unique_ptr<test::FakeEncodedFrame> MakeFrameWithResolution(
    VideoFrameType frame_type,
    int picture_id,
    int width,
    int height) {
  auto frame =
      test::FakeFrameBuilder().Id(picture_id).PayloadType(99).AsLast().Build();
  frame->SetFrameType(frame_type);
  frame->_encodedWidth = width;
  frame->_encodedHeight = height;
  return frame;
}

std::unique_ptr<test::FakeEncodedFrame> MakeFrame(VideoFrameType frame_type,
                                                  int picture_id) {
  return MakeFrameWithResolution(frame_type, picture_id, 320, 240);
}

TEST_P(VideoReceiveStream2Test, PassesFrameWhenEncodedFramesCallbackSet) {
  testing::MockFunction<void(const RecordableEncodedFrame&)> callback;
  video_receive_stream_->Start();
  EXPECT_CALL(callback, Call);
  video_receive_stream_->SetAndGetRecordingState(
      VideoReceiveStreamInterface::RecordingState(callback.AsStdFunction()),
      true);
  video_receive_stream_->OnCompleteFrame(
      MakeFrame(VideoFrameType::kVideoFrameKey, 0));
  EXPECT_TRUE(fake_renderer_.WaitForFrame(kDefaultTimeOut));

  EXPECT_THAT(rtcp_packet_parser_.pli()->num_packets(), Eq(1));

  video_receive_stream_->Stop();
}

TEST_P(VideoReceiveStream2Test, MovesEncodedFrameDispatchStateWhenReCreating) {
  testing::MockFunction<void(const RecordableEncodedFrame&)> callback;
  video_receive_stream_->Start();
  // Expect a key frame request over RTCP.
  video_receive_stream_->SetAndGetRecordingState(
      VideoReceiveStreamInterface::RecordingState(callback.AsStdFunction()),
      true);
  video_receive_stream_->Stop();
  VideoReceiveStreamInterface::RecordingState old_state =
      video_receive_stream_->SetAndGetRecordingState(
          VideoReceiveStreamInterface::RecordingState(), false);
  RecreateReceiveStream(std::move(old_state));

  EXPECT_THAT(rtcp_packet_parser_.pli()->num_packets(), Eq(1));

  video_receive_stream_->Stop();
}

TEST_P(VideoReceiveStream2Test, RequestsKeyFramesUntilKeyFrameReceived) {
  // Recreate receive stream with shorter delay to test rtx.
  TimeDelta rtx_delay = TimeDelta::Millis(50);
  config_.rtp.nack.rtp_history_ms = rtx_delay.ms();
  auto tick = rtx_delay / 2;
  RecreateReceiveStream();
  video_receive_stream_->Start();

  video_receive_stream_->GenerateKeyFrame();
  video_receive_stream_->OnCompleteFrame(
      MakeFrame(VideoFrameType::kVideoFrameDelta, 0));
  fake_renderer_.WaitForFrame(kDefaultTimeOut);
  time_controller_.AdvanceTime(tick);
  video_receive_stream_->OnCompleteFrame(
      MakeFrame(VideoFrameType::kVideoFrameDelta, 1));
  fake_renderer_.WaitForFrame(kDefaultTimeOut);
  time_controller_.AdvanceTime(TimeDelta::Zero());
  testing::Mock::VerifyAndClearExpectations(&mock_transport_);

  EXPECT_THAT(rtcp_packet_parser_.pli()->num_packets(), Eq(1));

  // T+keyframetimeout: still no key frame received, expect key frame request
  // sent again.
  time_controller_.AdvanceTime(tick);
  video_receive_stream_->OnCompleteFrame(
      MakeFrame(VideoFrameType::kVideoFrameDelta, 2));
  EXPECT_THAT(fake_renderer_.WaitForFrame(kDefaultTimeOut), RenderedFrame());
  testing::Mock::VerifyAndClearExpectations(&mock_transport_);

  EXPECT_THAT(rtcp_packet_parser_.pli()->num_packets(), Eq(2));

  // T+keyframetimeout: now send a key frame - we should not observe new key
  // frame requests after this.
  video_receive_stream_->OnCompleteFrame(
      MakeFrame(VideoFrameType::kVideoFrameKey, 3));
  EXPECT_THAT(fake_renderer_.WaitForFrame(kDefaultTimeOut), RenderedFrame());
  time_controller_.AdvanceTime(2 * tick);
  video_receive_stream_->OnCompleteFrame(
      MakeFrame(VideoFrameType::kVideoFrameDelta, 4));
  EXPECT_THAT(fake_renderer_.WaitForFrame(kDefaultTimeOut), RenderedFrame());

  EXPECT_THAT(rtcp_packet_parser_.pli()->num_packets(), Eq(2));
}

TEST_P(VideoReceiveStream2Test,
       DispatchesEncodedFrameSequenceStartingWithKeyframeWithoutResolution) {
  video_receive_stream_->Start();
  testing::MockFunction<void(const RecordableEncodedFrame&)> callback;
  video_receive_stream_->SetAndGetRecordingState(
      VideoReceiveStreamInterface::RecordingState(callback.AsStdFunction()),
      /*generate_key_frame=*/false);

  InSequence s;
  EXPECT_CALL(callback,
              Call(MatchResolution(test::FakeDecoder::kDefaultWidth,
                                   test::FakeDecoder::kDefaultHeight)));
  EXPECT_CALL(callback, Call);

  video_receive_stream_->OnCompleteFrame(
      MakeFrameWithResolution(VideoFrameType::kVideoFrameKey, 0, 0, 0));
  EXPECT_THAT(fake_renderer_.WaitForFrame(kDefaultTimeOut), RenderedFrame());
  video_receive_stream_->OnCompleteFrame(
      MakeFrameWithResolution(VideoFrameType::kVideoFrameDelta, 1, 0, 0));
  EXPECT_THAT(fake_renderer_.WaitForFrame(kDefaultTimeOut), RenderedFrame());

  video_receive_stream_->Stop();
}

TEST_P(VideoReceiveStream2Test,
       DispatchesEncodedFrameSequenceStartingWithKeyframeWithResolution) {
  video_receive_stream_->Start();
  testing::MockFunction<void(const RecordableEncodedFrame&)> callback;
  video_receive_stream_->SetAndGetRecordingState(
      VideoReceiveStreamInterface::RecordingState(callback.AsStdFunction()),
      /*generate_key_frame=*/false);

  InSequence s;
  EXPECT_CALL(callback, Call(MatchResolution(1080u, 720u)));
  EXPECT_CALL(callback, Call);

  video_receive_stream_->OnCompleteFrame(
      MakeFrameWithResolution(VideoFrameType::kVideoFrameKey, 0, 1080, 720));
  EXPECT_THAT(fake_renderer_.WaitForFrame(kDefaultTimeOut), RenderedFrame());
  video_receive_stream_->OnCompleteFrame(
      MakeFrameWithResolution(VideoFrameType::kVideoFrameDelta, 1, 0, 0));
  EXPECT_THAT(fake_renderer_.WaitForFrame(kDefaultTimeOut), RenderedFrame());

  video_receive_stream_->Stop();
}

TEST_P(VideoReceiveStream2Test, DependantFramesAreScheduled) {
  video_receive_stream_->Start();

  auto key_frame = test::FakeFrameBuilder()
                       .Id(0)
                       .PayloadType(99)
                       .Time(kFirstRtpTimestamp)
                       .ReceivedTime(kStartTime)
                       .AsLast()
                       .Build();
  auto delta_frame = test::FakeFrameBuilder()
                         .Id(1)
                         .PayloadType(99)
                         .Time(RtpTimestampForFrame(1))
                         .ReceivedTime(ReceiveTimeForFrame(1))
                         .Refs({0})
                         .AsLast()
                         .Build();

  // Expect frames are decoded in order.
  InSequence seq;
  EXPECT_CALL(mock_decoder_,
              Decode(test::RtpTimestamp(kFirstRtpTimestamp), _, _));
  EXPECT_CALL(mock_decoder_, Decode(test::RtpTimestamp(kFirstRtpTimestamp +
                                                       k30FpsRtpTimestampDelta),
                                    _, _))
      .Times(1);
  video_receive_stream_->OnCompleteFrame(std::move(key_frame));
  EXPECT_THAT(fake_renderer_.WaitForFrame(TimeDelta::Zero()), RenderedFrame());

  time_controller_.AdvanceTime(k30FpsDelay);
  video_receive_stream_->OnCompleteFrame(std::move(delta_frame));
  EXPECT_THAT(fake_renderer_.WaitForFrame(k30FpsDelay), RenderedFrame());

  video_receive_stream_->Stop();
}

TEST_P(VideoReceiveStream2Test, FramesScheduledInOrder) {
  video_receive_stream_->Start();

  auto key_frame = test::FakeFrameBuilder()
                       .Id(0)
                       .PayloadType(99)
                       .Time(kFirstRtpTimestamp)
                       .AsLast()
                       .Build();
  auto delta_frame1 = test::FakeFrameBuilder()
                          .Id(1)
                          .PayloadType(99)
                          .Time(RtpTimestampForFrame(1))
                          .Refs({0})
                          .AsLast()
                          .Build();
  auto delta_frame2 = test::FakeFrameBuilder()
                          .Id(2)
                          .PayloadType(99)
                          .Time(RtpTimestampForFrame(2))
                          .Refs({1})
                          .AsLast()
                          .Build();

  // Expect frames are decoded in order despite delta_frame1 arriving first.
  InSequence seq;
  EXPECT_CALL(mock_decoder_,
              Decode(test::RtpTimestamp(kFirstRtpTimestamp), _, _))
      .Times(1);
  EXPECT_CALL(mock_decoder_,
              Decode(test::RtpTimestamp(RtpTimestampForFrame(1)), _, _))
      .Times(1);
  EXPECT_CALL(mock_decoder_,
              Decode(test::RtpTimestamp(RtpTimestampForFrame(2)), _, _))
      .Times(1);
  key_frame->SetReceivedTime(clock_->CurrentTime().ms());
  video_receive_stream_->OnCompleteFrame(std::move(key_frame));
  EXPECT_THAT(fake_renderer_.WaitForFrame(TimeDelta::Zero()), RenderedFrame());

  delta_frame2->SetReceivedTime(clock_->CurrentTime().ms());
  video_receive_stream_->OnCompleteFrame(std::move(delta_frame2));
  EXPECT_THAT(fake_renderer_.WaitForFrame(k30FpsDelay), DidNotReceiveFrame());
  // `delta_frame1` arrives late.
  delta_frame1->SetReceivedTime(clock_->CurrentTime().ms());
  video_receive_stream_->OnCompleteFrame(std::move(delta_frame1));
  EXPECT_THAT(fake_renderer_.WaitForFrame(k30FpsDelay), RenderedFrame());
  EXPECT_THAT(fake_renderer_.WaitForFrame(k30FpsDelay * 2), RenderedFrame());
  video_receive_stream_->Stop();
}

TEST_P(VideoReceiveStream2Test, WaitsforAllSpatialLayers) {
  video_receive_stream_->Start();
  auto sl0 = test::FakeFrameBuilder()
                 .Id(0)
                 .PayloadType(99)
                 .Time(kFirstRtpTimestamp)
                 .ReceivedTime(kStartTime)
                 .Build();
  auto sl1 = test::FakeFrameBuilder()
                 .Id(1)
                 .PayloadType(99)
                 .ReceivedTime(kStartTime)
                 .Time(kFirstRtpTimestamp)
                 .Refs({0})
                 .Build();
  auto sl2 = test::FakeFrameBuilder()
                 .Id(2)
                 .PayloadType(99)
                 .ReceivedTime(kStartTime)
                 .Time(kFirstRtpTimestamp)
                 .Refs({0, 1})
                 .AsLast()
                 .Build();

  // No decodes should be called until `sl2` is received.
  EXPECT_CALL(mock_decoder_, Decode).Times(0);
  sl0->SetReceivedTime(clock_->CurrentTime().ms());
  video_receive_stream_->OnCompleteFrame(std::move(sl0));
  EXPECT_THAT(fake_renderer_.WaitForFrame(TimeDelta::Zero()),
              DidNotReceiveFrame());
  video_receive_stream_->OnCompleteFrame(std::move(sl1));
  EXPECT_THAT(fake_renderer_.WaitForFrame(TimeDelta::Zero()),
              DidNotReceiveFrame());
  // When `sl2` arrives decode should happen.
  EXPECT_CALL(mock_decoder_,
              Decode(test::RtpTimestamp(kFirstRtpTimestamp), _, _))
      .Times(1);
  video_receive_stream_->OnCompleteFrame(std::move(sl2));
  EXPECT_THAT(fake_renderer_.WaitForFrame(TimeDelta::Zero()), RenderedFrame());
  video_receive_stream_->Stop();
}

TEST_P(VideoReceiveStream2Test, FramesFastForwardOnSystemHalt) {
  video_receive_stream_->Start();

  // The frame structure looks like this,
  //   F1
  //   /
  // F0 --> F2
  //
  // In this case we will have a system halt simulated. By the time the system
  // resumes, F1 will be old and so F2 should be decoded.
  auto key_frame = test::FakeFrameBuilder()
                       .Id(0)
                       .PayloadType(99)
                       .Time(kFirstRtpTimestamp)
                       .AsLast()
                       .Build();
  auto ffwd_frame = test::FakeFrameBuilder()
                        .Id(1)
                        .PayloadType(99)
                        .Time(RtpTimestampForFrame(1))
                        .Refs({0})
                        .AsLast()
                        .Build();
  auto rendered_frame = test::FakeFrameBuilder()
                            .Id(2)
                            .PayloadType(99)
                            .Time(RtpTimestampForFrame(2))
                            .Refs({0})
                            .AsLast()
                            .Build();
  InSequence seq;
  EXPECT_CALL(mock_decoder_,
              Decode(test::RtpTimestamp(kFirstRtpTimestamp), _, _))
      .WillOnce(testing::DoAll(Invoke([&] {
                                 // System halt will be simulated in the decode.
                                 time_controller_.AdvanceTime(k30FpsDelay * 2);
                               }),
                               DefaultDecodeAction()));
  EXPECT_CALL(mock_decoder_,
              Decode(test::RtpTimestamp(RtpTimestampForFrame(2)), _, _));
  video_receive_stream_->OnCompleteFrame(std::move(key_frame));
  video_receive_stream_->OnCompleteFrame(std::move(ffwd_frame));
  video_receive_stream_->OnCompleteFrame(std::move(rendered_frame));
  EXPECT_THAT(fake_renderer_.WaitForFrame(TimeDelta::Zero()),
              RenderedFrameWith(RtpTimestamp(RtpTimestampForFrame(0))));
  EXPECT_THAT(fake_renderer_.WaitForFrame(TimeDelta::Zero()),
              RenderedFrameWith(RtpTimestamp(RtpTimestampForFrame(2))));

  // Check stats show correct dropped frames.
  auto stats = video_receive_stream_->GetStats();
  EXPECT_EQ(stats.frames_dropped, 1u);

  video_receive_stream_->Stop();
}

TEST_P(VideoReceiveStream2Test, BetterFrameInsertedWhileWaitingToDecodeFrame) {
  video_receive_stream_->Start();

  auto key_frame = test::FakeFrameBuilder()
                       .Id(0)
                       .PayloadType(99)
                       .Time(kFirstRtpTimestamp)
                       .ReceivedTime(ReceiveTimeForFrame(0))
                       .AsLast()
                       .Build();
  auto f1 = test::FakeFrameBuilder()
                .Id(1)
                .PayloadType(99)
                .Time(RtpTimestampForFrame(1))
                .ReceivedTime(ReceiveTimeForFrame(1))
                .Refs({0})
                .AsLast()
                .Build();
  auto f2 = test::FakeFrameBuilder()
                .Id(2)
                .PayloadType(99)
                .Time(RtpTimestampForFrame(2))
                .ReceivedTime(ReceiveTimeForFrame(2))
                .Refs({0})
                .AsLast()
                .Build();

  video_receive_stream_->OnCompleteFrame(std::move(key_frame));
  EXPECT_THAT(fake_renderer_.WaitForFrame(TimeDelta::Zero()), RenderedFrame());

  InSequence seq;
  EXPECT_CALL(mock_decoder_,
              Decode(test::RtpTimestamp(RtpTimestampForFrame(1)), _, _))
      .Times(1);
  EXPECT_CALL(mock_decoder_,
              Decode(test::RtpTimestamp(RtpTimestampForFrame(2)), _, _))
      .Times(1);
  // Simulate f1 arriving after f2 but before f2 is decoded.
  video_receive_stream_->OnCompleteFrame(std::move(f2));
  EXPECT_THAT(fake_renderer_.WaitForFrame(k30FpsDelay), DidNotReceiveFrame());
  video_receive_stream_->OnCompleteFrame(std::move(f1));
  EXPECT_THAT(fake_renderer_.WaitForFrame(k30FpsDelay), RenderedFrame());
  EXPECT_THAT(fake_renderer_.WaitForFrame(k30FpsDelay), RenderedFrame());

  video_receive_stream_->Stop();
}

// Note: This test takes a long time (~10s) to run if the fake metronome is
// active. Since the test needs to wait for the timestamp to rollover, it has a
// fake delay of around 6.5 hours. Even though time is simulated, this will be
// around 1,500,000 metronome tick invocations.
TEST_P(VideoReceiveStream2Test, RtpTimestampWrapAround) {
  EXPECT_CALL(mock_transport_, SendRtcp).Times(AnyNumber());
  video_receive_stream_->Start();

  constexpr uint32_t kBaseRtp = std::numeric_limits<uint32_t>::max() / 2;
  video_receive_stream_->OnCompleteFrame(
      test::FakeFrameBuilder()
          .Id(0)
          .PayloadType(99)
          .Time(kBaseRtp)
          .ReceivedTime(clock_->CurrentTime())
          .AsLast()
          .Build());
  EXPECT_THAT(fake_renderer_.WaitForFrame(TimeDelta::Zero()), RenderedFrame());
  time_controller_.AdvanceTime(k30FpsDelay);
  video_receive_stream_->OnCompleteFrame(
      test::FakeFrameBuilder()
          .Id(1)
          .PayloadType(99)
          .Time(kBaseRtp + k30FpsRtpTimestampDelta)
          .ReceivedTime(clock_->CurrentTime())
          .AsLast()
          .Build());
  EXPECT_THAT(fake_renderer_.WaitForFrame(k30FpsDelay), RenderedFrame());

  // Pause stream so that RTP timestamp wraps around.
  constexpr uint32_t kLastRtp = kBaseRtp + k30FpsRtpTimestampDelta;
  constexpr uint32_t kWrapAroundRtp =
      kLastRtp + std::numeric_limits<uint32_t>::max() / 2 + 1;
  // Pause for corresponding delay such that RTP timestamp would increase this
  // much at 30fps.
  constexpr TimeDelta kWrapAroundDelay =
      (std::numeric_limits<uint32_t>::max() / 2 + 1) / kRtpTimestampHz;

  time_controller_.AdvanceTime(kWrapAroundDelay);
  video_receive_stream_->OnCompleteFrame(
      test::FakeFrameBuilder()
          .Id(2)
          .PayloadType(99)
          .Time(kWrapAroundRtp)
          .ReceivedTime(clock_->CurrentTime())
          .AsLast()
          .Build());
  EXPECT_CALL(mock_decoder_, Decode(test::RtpTimestamp(kWrapAroundRtp), _, _))
      .Times(1);
  EXPECT_THAT(fake_renderer_.WaitForFrame(TimeDelta::Zero()), RenderedFrame());

  video_receive_stream_->Stop();
}

// If a frame was lost causing the stream to become temporarily non-decodable
// and the sender reduces their framerate during this time, the video stream
// should start decoding at the new framerate. However, if the connection is
// poor, a keyframe will take a long time to send. If the timing of the incoming
// frames was not kept up to date with the new framerate while the stream was
// decodable, this late frame will have a large delay as the rtp timestamp of
// this keyframe will look like the frame arrived early if the frame-rate was
// not updated.
TEST_P(VideoReceiveStream2Test, PoorConnectionWithFpsChangeDuringLostFrame) {
  video_receive_stream_->Start();

  constexpr Frequency k15Fps = Frequency::Hertz(15);
  constexpr TimeDelta k15FpsDelay = 1 / k15Fps;
  constexpr uint32_t k15FpsRtpTimestampDelta = kRtpTimestampHz / k15Fps;

  // Initial keyframe and frames at 30fps.
  video_receive_stream_->OnCompleteFrame(
      test::FakeFrameBuilder()
          .Id(0)
          .PayloadType(99)
          .Time(RtpTimestampForFrame(0))
          .ReceivedTime(ReceiveTimeForFrame(0))
          .AsLast()
          .Build());
  EXPECT_THAT(fake_renderer_.WaitForFrame(k30FpsDelay, /*advance_time=*/true),
              RenderedFrameWith(RtpTimestamp(RtpTimestampForFrame(0))));

  video_receive_stream_->OnCompleteFrame(
      test::FakeFrameBuilder()
          .Id(1)
          .PayloadType(99)
          .Time(RtpTimestampForFrame(1))
          .ReceivedTime(ReceiveTimeForFrame(1))
          .Refs({0})
          .AsLast()
          .Build());
  EXPECT_THAT(fake_renderer_.WaitForFrame(k30FpsDelay, /*advance_time=*/true),
              RenderedFrameWith(RtpTimestamp(RtpTimestampForFrame(1))));

  // Simulate lost frame 2, followed by 2 second of frames at 30fps, followed by
  // 2 second of frames at 15 fps, and then a keyframe.
  time_controller_.AdvanceTime(k30FpsDelay);

  Timestamp send_30fps_end_time = clock_->CurrentTime() + TimeDelta::Seconds(2);
  int id = 3;
  EXPECT_CALL(mock_transport_, SendRtcp).Times(AnyNumber());
  while (clock_->CurrentTime() < send_30fps_end_time) {
    ++id;
    video_receive_stream_->OnCompleteFrame(
        test::FakeFrameBuilder()
            .Id(id)
            .PayloadType(99)
            .Time(RtpTimestampForFrame(id))
            .ReceivedTime(ReceiveTimeForFrame(id))
            .Refs({id - 1})
            .AsLast()
            .Build());
    EXPECT_THAT(fake_renderer_.WaitForFrame(k30FpsDelay, /*advance_time=*/true),
                Eq(absl::nullopt));
  }
  uint32_t current_rtp = RtpTimestampForFrame(id);
  Timestamp send_15fps_end_time = clock_->CurrentTime() + TimeDelta::Seconds(2);
  while (clock_->CurrentTime() < send_15fps_end_time) {
    ++id;
    current_rtp += k15FpsRtpTimestampDelta;
    video_receive_stream_->OnCompleteFrame(
        test::FakeFrameBuilder()
            .Id(id)
            .PayloadType(99)
            .Time(current_rtp)
            .ReceivedTime(clock_->CurrentTime())
            .Refs({id - 1})
            .AsLast()
            .Build());
    EXPECT_THAT(fake_renderer_.WaitForFrame(k15FpsDelay, /*advance_time=*/true),
                Eq(absl::nullopt));
  }

  ++id;
  current_rtp += k15FpsRtpTimestampDelta;
  // Insert keyframe which will recover the stream. However, on a poor
  // connection the keyframe will take significant time to send.
  constexpr TimeDelta kKeyframeDelay = TimeDelta::Millis(200);
  video_receive_stream_->OnCompleteFrame(
      test::FakeFrameBuilder()
          .Id(id)
          .PayloadType(99)
          .Time(current_rtp)
          .ReceivedTime(clock_->CurrentTime() + kKeyframeDelay)
          .AsLast()
          .Build());
  // If the framerate was not updated to be 15fps from the frames that arrived
  // previously, this will fail, as the delay will be longer.
  EXPECT_THAT(fake_renderer_.WaitForFrame(k15FpsDelay, /*advance_time=*/true),
              RenderedFrameWith(RtpTimestamp(current_rtp)));

  video_receive_stream_->Stop();
}

TEST_P(VideoReceiveStream2Test, StreamShouldNotTimeoutWhileWaitingForFrame) {
  // Disable smoothing since this makes it hard to test frame timing.
  config_.enable_prerenderer_smoothing = false;
  RecreateReceiveStream();

  video_receive_stream_->Start();
  EXPECT_CALL(mock_transport_, SendRtcp).Times(AnyNumber());

  video_receive_stream_->OnCompleteFrame(
      test::FakeFrameBuilder()
          .Id(0)
          .PayloadType(99)
          .Time(RtpTimestampForFrame(0))
          .ReceivedTime(ReceiveTimeForFrame(0))
          .AsLast()
          .Build());
  EXPECT_THAT(fake_renderer_.WaitForFrame(k30FpsDelay, /*advance_time=*/true),
              RenderedFrameWith(RtpTimestamp(RtpTimestampForFrame(0))));

  for (int id = 1; id < 30; ++id) {
    video_receive_stream_->OnCompleteFrame(
        test::FakeFrameBuilder()
            .Id(id)
            .PayloadType(99)
            .Time(RtpTimestampForFrame(id))
            .ReceivedTime(ReceiveTimeForFrame(id))
            .Refs({0})
            .AsLast()
            .Build());
    EXPECT_THAT(fake_renderer_.WaitForFrame(k30FpsDelay, /*advance_time=*/true),
                RenderedFrameWith(RtpTimestamp(RtpTimestampForFrame(id))));
  }

  // Simulate a pause in the stream, followed by a decodable frame that is ready
  // long in the future. The stream should not timeout in this case, but rather
  // decode the frame just before the timeout.
  time_controller_.AdvanceTime(TimeDelta::Millis(2900));
  uint32_t late_decode_rtp = kFirstRtpTimestamp + 200 * k30FpsRtpTimestampDelta;
  video_receive_stream_->OnCompleteFrame(
      test::FakeFrameBuilder()
          .Id(121)
          .PayloadType(99)
          .Time(late_decode_rtp)
          .ReceivedTime(clock_->CurrentTime())
          .AsLast()
          .Build());
  EXPECT_THAT(fake_renderer_.WaitForFrame(TimeDelta::Millis(100),
                                          /*advance_time=*/true),
              RenderedFrameWith(RtpTimestamp(late_decode_rtp)));

  video_receive_stream_->Stop();
}

INSTANTIATE_TEST_SUITE_P(VideoReceiveStream2Test,
                         VideoReceiveStream2Test,
                         testing::Bool(),
                         [](const auto& test_param_info) {
                           return (test_param_info.param
                                       ? "ScheduleDecodesWithMetronome"
                                       : "ScheduleDecodesWithPostTask");
                         });

}  // namespace webrtc
