Create unit test for the population of capture_start_ntp_time

This verifies that receiving two RTCP SR packets is enough to get
a defined capture start time stat.

Bug: webrtc:13931
Change-Id: Ib5f7c2954eab6500917f25c44f523d3aedae5e94
Reviewed-on: https://webrtc-review.googlesource.com/c/src/+/291520
Reviewed-by: Danil Chapovalov <danilchap@webrtc.org>
Commit-Queue: Harald Alvestrand <hta@webrtc.org>
Cr-Commit-Position: refs/heads/main@{#39261}
diff --git a/audio/BUILD.gn b/audio/BUILD.gn
index a144540..fc7e12e 100644
--- a/audio/BUILD.gn
+++ b/audio/BUILD.gn
@@ -226,14 +226,17 @@
     sources = [ "channel_receive_unittest.cc" ]
     deps = [
       ":audio",
+      "../api/audio_codecs:builtin_audio_decoder_factory",
       "../api/crypto:frame_decryptor_interface",
       "../api/task_queue:default_task_queue_factory",
       "../logging:mocks",
       "../modules/audio_device:audio_device_api",
       "../modules/audio_device:mock_audio_device",
+      "../modules/rtp_rtcp",
       "../modules/rtp_rtcp:rtp_rtcp_format",
       "../rtc_base:logging",
       "../rtc_base:threading",
+      "../test:audio_codec_mocks",
       "../test:mock_transport",
       "../test:test_support",
       "../test/time_controller",
diff --git a/audio/channel_receive_unittest.cc b/audio/channel_receive_unittest.cc
index b5654e2..250ad4c 100644
--- a/audio/channel_receive_unittest.cc
+++ b/audio/channel_receive_unittest.cc
@@ -10,6 +10,8 @@
 
 #include "audio/channel_receive.h"
 
+#include "absl/strings/escaping.h"
+#include "api/audio_codecs/builtin_audio_decoder_factory.h"
 #include "api/crypto/frame_decryptor_interface.h"
 #include "api/task_queue/default_task_queue_factory.h"
 #include "logging/rtc_event_log/mock/mock_rtc_event_log.h"
@@ -17,10 +19,16 @@
 #include "modules/audio_device/include/mock_audio_device.h"
 #include "modules/rtp_rtcp/source/byte_io.h"
 #include "modules/rtp_rtcp/source/rtcp_packet/receiver_report.h"
+#include "modules/rtp_rtcp/source/rtcp_packet/report_block.h"
+#include "modules/rtp_rtcp/source/rtcp_packet/sdes.h"
+#include "modules/rtp_rtcp/source/rtcp_packet/sender_report.h"
+#include "modules/rtp_rtcp/source/rtp_packet_received.h"
+#include "modules/rtp_rtcp/source/time_util.h"
 #include "rtc_base/logging.h"
 #include "rtc_base/thread.h"
 #include "test/gmock.h"
 #include "test/gtest.h"
+#include "test/mock_audio_decoder_factory.h"
 #include "test/mock_transport.h"
 #include "test/time_controller/simulated_time_controller.h"
 
@@ -30,38 +38,126 @@
 
 using ::testing::NiceMock;
 using ::testing::NotNull;
+using ::testing::Return;
 using ::testing::Test;
 
 constexpr uint32_t kLocalSsrc = 1111;
 constexpr uint32_t kRemoteSsrc = 2222;
+// We run RTP data with 8 kHz PCMA (fixed payload type 8).
+constexpr char kPayloadName[] = "PCMA";
+constexpr int kPayloadType = 8;
+constexpr int kSampleRateHz = 8000;
 
 class ChannelReceiveTest : public Test {
  public:
   ChannelReceiveTest()
       : time_controller_(Timestamp::Seconds(5555)),
-        audio_device_module_(test::MockAudioDeviceModule::CreateStrict()) {}
+        audio_device_module_(test::MockAudioDeviceModule::CreateNice()),
+        audio_decoder_factory_(CreateBuiltinAudioDecoderFactory()) {
+    ON_CALL(*audio_device_module_, PlayoutDelay).WillByDefault(Return(0));
+  }
 
   std::unique_ptr<ChannelReceiveInterface> CreateTestChannelReceive() {
     CryptoOptions crypto_options;
-    return CreateChannelReceive(
+    auto channel = CreateChannelReceive(
         time_controller_.GetClock(),
         /* neteq_factory= */ nullptr, audio_device_module_.get(), &transport_,
         &event_log_, kLocalSsrc, kRemoteSsrc,
         /* jitter_buffer_max_packets= */ 0,
         /* jitter_buffer_fast_playout= */ false,
         /* jitter_buffer_min_delay_ms= */ 0,
-        /* enable_non_sender_rtt= */ false,
-        /* decoder_factory= */ nullptr,
+        /* enable_non_sender_rtt= */ false, audio_decoder_factory_,
         /* codec_pair_id= */ absl::nullopt,
         /* frame_decryptor_interface= */ nullptr, crypto_options,
         /* frame_transformer= */ nullptr);
+    channel->SetReceiveCodecs(
+        {{kPayloadType, {kPayloadName, kSampleRateHz, 1}}});
+    return channel;
   }
 
   NtpTime NtpNow() { return time_controller_.GetClock()->CurrentNtpTime(); }
 
+  uint32_t RtpNow() {
+    // Note - the "random" offset of this timestamp is zero.
+    return rtc::TimeMillis() * 1000 / kSampleRateHz;
+  }
+
+  RtpPacketReceived CreateRtpPacket() {
+    RtpPacketReceived packet;
+    packet.set_arrival_time(time_controller_.GetClock()->CurrentTime());
+    packet.SetTimestamp(RtpNow());
+    packet.SetSsrc(kLocalSsrc);
+    packet.SetPayloadType(kPayloadType);
+    // Packet size should be enough to give at least 10 ms of data.
+    // For PCMA, that's 80 bytes; this should be enough.
+    uint8_t* datapos = packet.SetPayloadSize(100);
+    memset(datapos, 0, 100);
+    return packet;
+  }
+
+  std::vector<uint8_t> CreateRtcpSenderReport() {
+    std::vector<uint8_t> packet(1024);
+    size_t pos = 0;
+    rtcp::SenderReport report;
+    report.SetSenderSsrc(kRemoteSsrc);
+    report.SetNtp(NtpNow());
+    report.SetRtpTimestamp(RtpNow());
+    report.SetPacketCount(0);
+    report.SetOctetCount(0);
+    report.Create(&packet[0], &pos, packet.size(), nullptr);
+    // No report blocks.
+    packet.resize(pos);
+    return packet;
+  }
+
+  std::vector<uint8_t> CreateRtcpReceiverReport() {
+    rtcp::ReportBlock block;
+    block.SetMediaSsrc(kLocalSsrc);
+    // Middle 32 bits of the NTP timestamp from received SR
+    block.SetLastSr(CompactNtp(NtpNow()));
+    block.SetDelayLastSr(0);
+
+    rtcp::ReceiverReport report;
+    report.SetSenderSsrc(kRemoteSsrc);
+    report.AddReportBlock(block);
+
+    std::vector<uint8_t> packet(1024);
+    size_t pos = 0;
+    report.Create(&packet[0], &pos, packet.size(), nullptr);
+    packet.resize(pos);
+    return packet;
+  }
+
+  void HandleGeneratedRtcp(ChannelReceiveInterface& channel,
+                           rtc::ArrayView<const uint8_t> packet) {
+    if (packet[1] == rtcp::ReceiverReport::kPacketType) {
+      // Ignore RR, it requires no response
+    } else {
+      RTC_LOG(LS_ERROR) << "Unexpected RTCP packet generated";
+      RTC_LOG(LS_ERROR) << "Packet content "
+                        << rtc::hex_encode_with_delimiter(
+                               absl::string_view(
+                                   reinterpret_cast<char*>(packet.data()[0]),
+                                   packet.size()),
+                               ' ');
+    }
+  }
+
+  int64_t ProbeCaptureStartNtpTime(ChannelReceiveInterface& channel) {
+    // Computation of the capture_start_ntp_time_ms_ occurs when the
+    // audio data is pulled, not when it is received. So we need to
+    // inject an RTP packet, and then fetch its data.
+    AudioFrame audio_frame;
+    channel.OnRtpPacket(CreateRtpPacket());
+    channel.GetAudioFrameWithInfo(kSampleRateHz, &audio_frame);
+    CallReceiveStatistics stats = channel.GetRTCPStatistics();
+    return stats.capture_start_ntp_time_ms_;
+  }
+
  protected:
   GlobalSimulatedTimeController time_controller_;
   rtc::scoped_refptr<test::MockAudioDeviceModule> audio_device_module_;
+  rtc::scoped_refptr<AudioDecoderFactory> audio_decoder_factory_;
   MockTransport transport_;
   NiceMock<MockRtcEventLog> event_log_;
 };
@@ -73,7 +169,6 @@
 
 TEST_F(ChannelReceiveTest, ReceiveReportGeneratedOnTime) {
   auto channel = CreateTestChannelReceive();
-  channel->SetReceiveCodecs({{10, {"L16", 44100, 1}}});
 
   bool receiver_report_sent = false;
   EXPECT_CALL(transport_, SendRtcp)
@@ -90,6 +185,46 @@
   EXPECT_TRUE(receiver_report_sent);
 }
 
+TEST_F(ChannelReceiveTest, CaptureStartTimeBecomesValid) {
+  auto channel = CreateTestChannelReceive();
+
+  EXPECT_CALL(transport_, SendRtcp)
+      .WillRepeatedly([&](const uint8_t* packet, size_t length) {
+        HandleGeneratedRtcp(*channel, rtc::MakeArrayView(packet, length));
+        return true;
+      });
+  // Before any packets are sent, CaptureStartTime is invalid.
+  EXPECT_EQ(ProbeCaptureStartNtpTime(*channel), -1);
+
+  // Must start playout, otherwise packet is discarded.
+  channel->StartPlayout();
+  // Send one RTP packet. This causes registration of the SSRC.
+  channel->OnRtpPacket(CreateRtpPacket());
+  EXPECT_EQ(ProbeCaptureStartNtpTime(*channel), -1);
+
+  // Receive a sender report.
+  auto rtcp_packet_1 = CreateRtcpSenderReport();
+  channel->ReceivedRTCPPacket(rtcp_packet_1.data(), rtcp_packet_1.size());
+  EXPECT_EQ(ProbeCaptureStartNtpTime(*channel), -1);
+
+  time_controller_.AdvanceTime(TimeDelta::Seconds(5));
+
+  // Receive a receiver report. This is necessary, which is odd.
+  // Presumably it is because the receiver needs to know the RTT
+  // before it can compute the capture start NTP time.
+  // The receiver report must happen before the second sender report.
+  auto rtcp_rr = CreateRtcpReceiverReport();
+  channel->ReceivedRTCPPacket(rtcp_rr.data(), rtcp_rr.size());
+  EXPECT_EQ(ProbeCaptureStartNtpTime(*channel), -1);
+
+  // Receive another sender report after 5 seconds.
+  // This should be enough to establish the capture start NTP time.
+  auto rtcp_packet_2 = CreateRtcpSenderReport();
+  channel->ReceivedRTCPPacket(rtcp_packet_2.data(), rtcp_packet_2.size());
+
+  EXPECT_NE(ProbeCaptureStartNtpTime(*channel), -1);
+}
+
 }  // namespace
 }  // namespace voe
 }  // namespace webrtc