Implement RTCRemoteInboundRtpStreamStats for both audio and video.

This implements the essentials of RTCRemoteInboundRtpStreamStats. This
includes:
- ssrc
- transportId
- codecId
- packetsLost
- jitter
- localId
- roundTripTime
https://w3c.github.io/webrtc-stats/#remoteinboundrtpstats-dict*

The following members are not implemented because they require more
work...
- From RTCReceivedRtpStreamStats: packetsReceived, packetsDiscarded,
  packetsRepaired, burstPacketsLost, burstPacketsDiscarded,
  burstLossCount, burstDiscardCount, burstLossRate, burstDiscardRate,
  gapLossRate and gapDiscardRate.
- From RTCRemoteInboundRtpStreamStats: fractionLost.

Bug: webrtc:10455, webrtc:10456
Change-Id: If2ab0da7105d8c93bba58e14aa93bd22ffe57f1d
Reviewed-on: https://webrtc-review.googlesource.com/c/src/+/138067
Commit-Queue: Henrik Boström <hbos@webrtc.org>
Reviewed-by: Harald Alvestrand <hta@webrtc.org>
Cr-Commit-Position: refs/heads/master@{#28073}
diff --git a/pc/rtc_stats_collector_unittest.cc b/pc/rtc_stats_collector_unittest.cc
index 6cd6319..c8876bf 100644
--- a/pc/rtc_stats_collector_unittest.cc
+++ b/pc/rtc_stats_collector_unittest.cc
@@ -8,6 +8,9 @@
  *  be found in the AUTHORS file in the root of the source tree.
  */
 
+#include <ctype.h>
+
+#include <algorithm>
 #include <initializer_list>
 #include <memory>
 #include <ostream>
@@ -21,6 +24,8 @@
 #include "api/stats/rtc_stats_report.h"
 #include "api/stats/rtcstats_objects.h"
 #include "api/units/time_delta.h"
+#include "modules/rtp_rtcp/include/report_block_data.h"
+#include "modules/rtp_rtcp/include/rtp_rtcp_defines.h"
 #include "p2p/base/p2p_constants.h"
 #include "p2p/base/port.h"
 #include "pc/media_stream.h"
@@ -89,6 +94,10 @@
   *os << stats.ToJson();
 }
 
+void PrintTo(const RTCRemoteInboundRtpStreamStats& stats, ::std::ostream* os) {
+  *os << stats.ToJson();
+}
+
 void PrintTo(const RTCAudioSourceStats& stats, ::std::ostream* os) {
   *os << stats.ToJson();
 }
@@ -2342,6 +2351,252 @@
   EXPECT_FALSE(report->Get("RTCAudioSource_42"));
 }
 
+// Parameterized tests on cricket::MediaType (audio or video).
+class RTCStatsCollectorTestWithParamKind
+    : public RTCStatsCollectorTest,
+      public ::testing::WithParamInterface<cricket::MediaType> {
+ public:
+  RTCStatsCollectorTestWithParamKind() : media_type_(GetParam()) {
+    RTC_DCHECK(media_type_ == cricket::MEDIA_TYPE_AUDIO ||
+               media_type_ == cricket::MEDIA_TYPE_VIDEO);
+  }
+
+  std::string MediaTypeUpperCase() const {
+    switch (media_type_) {
+      case cricket::MEDIA_TYPE_AUDIO:
+        return "Audio";
+      case cricket::MEDIA_TYPE_VIDEO:
+        return "Video";
+      case cricket::MEDIA_TYPE_DATA:
+        RTC_NOTREACHED();
+        return "";
+    }
+  }
+
+  std::string MediaTypeLowerCase() const {
+    std::string str = MediaTypeUpperCase();
+    std::transform(str.begin(), str.end(), str.begin(), ::tolower);
+    return str;
+  }
+
+  // Adds a sender and channel of the appropriate kind, creating a sender info
+  // with the report block's |source_ssrc| and report block data.
+  void AddSenderInfoAndMediaChannel(std::string transport_name,
+                                    ReportBlockData report_block_data,
+                                    absl::optional<RtpCodecParameters> codec) {
+    switch (media_type_) {
+      case cricket::MEDIA_TYPE_AUDIO: {
+        cricket::VoiceMediaInfo voice_media_info;
+        voice_media_info.senders.push_back(cricket::VoiceSenderInfo());
+        voice_media_info.senders[0].local_stats.push_back(
+            cricket::SsrcSenderInfo());
+        voice_media_info.senders[0].local_stats[0].ssrc =
+            report_block_data.report_block().source_ssrc;
+        if (codec.has_value()) {
+          voice_media_info.senders[0].codec_payload_type = codec->payload_type;
+          voice_media_info.send_codecs.insert(
+              std::make_pair(codec->payload_type, *codec));
+        }
+        voice_media_info.senders[0].report_block_datas.push_back(
+            report_block_data);
+        auto* voice_media_channel = pc_->AddVoiceChannel("mid", transport_name);
+        voice_media_channel->SetStats(voice_media_info);
+        return;
+      }
+      case cricket::MEDIA_TYPE_VIDEO: {
+        cricket::VideoMediaInfo video_media_info;
+        video_media_info.senders.push_back(cricket::VideoSenderInfo());
+        video_media_info.senders[0].local_stats.push_back(
+            cricket::SsrcSenderInfo());
+        video_media_info.senders[0].local_stats[0].ssrc =
+            report_block_data.report_block().source_ssrc;
+        if (codec.has_value()) {
+          video_media_info.senders[0].codec_payload_type = codec->payload_type;
+          video_media_info.send_codecs.insert(
+              std::make_pair(codec->payload_type, *codec));
+        }
+        video_media_info.senders[0].report_block_datas.push_back(
+            report_block_data);
+        auto* video_media_channel = pc_->AddVideoChannel("mid", transport_name);
+        video_media_channel->SetStats(video_media_info);
+        return;
+      }
+      case cricket::MEDIA_TYPE_DATA:
+        RTC_NOTREACHED();
+    }
+  }
+
+ protected:
+  cricket::MediaType media_type_;
+};
+
+// Verifies RTCRemoteInboundRtpStreamStats members that don't require
+// RTCCodecStats (codecId, jitter) and without setting up an RTCP transport.
+TEST_P(RTCStatsCollectorTestWithParamKind,
+       RTCRemoteInboundRtpStreamStatsCollectedFromReportBlock) {
+  const int64_t kReportBlockTimestampUtcUs = 123456789;
+  const int64_t kRoundTripTimeMs = 13000;
+  const double kRoundTripTimeSeconds = 13.0;
+
+  // The report block's timestamp cannot be from the future, set the fake clock
+  // to match.
+  fake_clock_.SetTime(Timestamp::us(kReportBlockTimestampUtcUs));
+
+  RTCPReportBlock report_block;
+  // The remote-inbound-rtp SSRC, "SSRC of sender of this report".
+  report_block.sender_ssrc = 8;
+  // The outbound-rtp SSRC, "SSRC of the RTP packet sender".
+  report_block.source_ssrc = 12;
+  report_block.packets_lost = 7;
+  ReportBlockData report_block_data;
+  report_block_data.SetReportBlock(report_block, kReportBlockTimestampUtcUs);
+  report_block_data.AddRoundTripTimeSample(1234);
+  // Only the last sample should be exposed as the
+  // |RTCRemoteInboundRtpStreamStats::round_trip_time|.
+  report_block_data.AddRoundTripTimeSample(kRoundTripTimeMs);
+
+  AddSenderInfoAndMediaChannel("TransportName", report_block_data,
+                               absl::nullopt);
+
+  rtc::scoped_refptr<const RTCStatsReport> report = stats_->GetStatsReport();
+
+  RTCRemoteInboundRtpStreamStats expected_remote_inbound_rtp(
+      "RTCRemoteInboundRtp" + MediaTypeUpperCase() + "Stream_8_12",
+      kReportBlockTimestampUtcUs);
+  expected_remote_inbound_rtp.ssrc = 8;
+  expected_remote_inbound_rtp.kind = MediaTypeLowerCase();
+  expected_remote_inbound_rtp.transport_id =
+      "RTCTransport_TransportName_1";  // 1 for RTP (we have no RTCP transport)
+  expected_remote_inbound_rtp.packets_lost = 7;
+  expected_remote_inbound_rtp.local_id =
+      "RTCOutboundRTP" + MediaTypeUpperCase() + "Stream_12";
+  expected_remote_inbound_rtp.round_trip_time = kRoundTripTimeSeconds;
+  // This test does not set up RTCCodecStats, so |codec_id| and |jitter| are
+  // expected to be missing. These are tested separately.
+
+  ASSERT_TRUE(report->Get(expected_remote_inbound_rtp.id()));
+  EXPECT_EQ(report->Get(expected_remote_inbound_rtp.id())
+                ->cast_to<RTCRemoteInboundRtpStreamStats>(),
+            expected_remote_inbound_rtp);
+  EXPECT_TRUE(report->Get(*expected_remote_inbound_rtp.transport_id));
+  EXPECT_TRUE(report->Get(*expected_remote_inbound_rtp.local_id));
+}
+
+TEST_P(RTCStatsCollectorTestWithParamKind,
+       RTCRemoteInboundRtpStreamStatsWithTimestampFromReportBlock) {
+  const int64_t kReportBlockTimestampUtcUs = 123456789;
+  fake_clock_.SetTime(Timestamp::us(kReportBlockTimestampUtcUs));
+
+  RTCPReportBlock report_block;
+  // The remote-inbound-rtp SSRC, "SSRC of sender of this report".
+  report_block.sender_ssrc = 8;
+  // The outbound-rtp SSRC, "SSRC of the RTP packet sender".
+  report_block.source_ssrc = 12;
+  ReportBlockData report_block_data;
+  report_block_data.SetReportBlock(report_block, kReportBlockTimestampUtcUs);
+
+  AddSenderInfoAndMediaChannel("TransportName", report_block_data,
+                               absl::nullopt);
+
+  // Advance time, it should be OK to have fresher reports than report blocks.
+  fake_clock_.AdvanceTime(TimeDelta::us(1234));
+
+  rtc::scoped_refptr<const RTCStatsReport> report = stats_->GetStatsReport();
+
+  std::string remote_inbound_rtp_id =
+      "RTCRemoteInboundRtp" + MediaTypeUpperCase() + "Stream_8_12";
+  ASSERT_TRUE(report->Get(remote_inbound_rtp_id));
+  auto& remote_inbound_rtp = report->Get(remote_inbound_rtp_id)
+                                 ->cast_to<RTCRemoteInboundRtpStreamStats>();
+
+  // Even though the report time is different, the remote-inbound-rtp timestamp
+  // is of the time that the report block was received.
+  EXPECT_EQ(kReportBlockTimestampUtcUs + 1234, report->timestamp_us());
+  EXPECT_EQ(kReportBlockTimestampUtcUs, remote_inbound_rtp.timestamp_us());
+}
+
+TEST_P(RTCStatsCollectorTestWithParamKind,
+       RTCRemoteInboundRtpStreamStatsWithCodecBasedMembers) {
+  const int64_t kReportBlockTimestampUtcUs = 123456789;
+  fake_clock_.SetTime(Timestamp::us(kReportBlockTimestampUtcUs));
+
+  RTCPReportBlock report_block;
+  // The remote-inbound-rtp SSRC, "SSRC of sender of this report".
+  report_block.sender_ssrc = 8;
+  // The outbound-rtp SSRC, "SSRC of the RTP packet sender".
+  report_block.source_ssrc = 12;
+  report_block.jitter = 5000;
+  ReportBlockData report_block_data;
+  report_block_data.SetReportBlock(report_block, kReportBlockTimestampUtcUs);
+
+  RtpCodecParameters codec;
+  codec.payload_type = 3;
+  codec.kind = media_type_;
+  codec.clock_rate = 1000;
+
+  AddSenderInfoAndMediaChannel("TransportName", report_block_data, codec);
+
+  rtc::scoped_refptr<const RTCStatsReport> report = stats_->GetStatsReport();
+
+  std::string remote_inbound_rtp_id =
+      "RTCRemoteInboundRtp" + MediaTypeUpperCase() + "Stream_8_12";
+  ASSERT_TRUE(report->Get(remote_inbound_rtp_id));
+  auto& remote_inbound_rtp = report->Get(remote_inbound_rtp_id)
+                                 ->cast_to<RTCRemoteInboundRtpStreamStats>();
+
+  EXPECT_TRUE(remote_inbound_rtp.codec_id.is_defined());
+  EXPECT_TRUE(report->Get(*remote_inbound_rtp.codec_id));
+
+  EXPECT_TRUE(remote_inbound_rtp.jitter.is_defined());
+  // The jitter (in seconds) is the report block's jitter divided by the codec's
+  // clock rate.
+  EXPECT_EQ(5.0, *remote_inbound_rtp.jitter);
+}
+
+TEST_P(RTCStatsCollectorTestWithParamKind,
+       RTCRemoteInboundRtpStreamStatsWithRtcpTransport) {
+  const int64_t kReportBlockTimestampUtcUs = 123456789;
+  fake_clock_.SetTime(Timestamp::us(kReportBlockTimestampUtcUs));
+
+  RTCPReportBlock report_block;
+  // The remote-inbound-rtp SSRC, "SSRC of sender of this report".
+  report_block.sender_ssrc = 8;
+  // The outbound-rtp SSRC, "SSRC of the RTP packet sender".
+  report_block.source_ssrc = 12;
+  ReportBlockData report_block_data;
+  report_block_data.SetReportBlock(report_block, kReportBlockTimestampUtcUs);
+
+  cricket::TransportChannelStats rtp_transport_channel_stats;
+  rtp_transport_channel_stats.component = cricket::ICE_CANDIDATE_COMPONENT_RTP;
+  rtp_transport_channel_stats.dtls_state = cricket::DTLS_TRANSPORT_NEW;
+  cricket::TransportChannelStats rtcp_transport_channel_stats;
+  rtcp_transport_channel_stats.component =
+      cricket::ICE_CANDIDATE_COMPONENT_RTCP;
+  rtcp_transport_channel_stats.dtls_state = cricket::DTLS_TRANSPORT_NEW;
+  pc_->SetTransportStats("TransportName", {rtp_transport_channel_stats,
+                                           rtcp_transport_channel_stats});
+  AddSenderInfoAndMediaChannel("TransportName", report_block_data,
+                               absl::nullopt);
+
+  rtc::scoped_refptr<const RTCStatsReport> report = stats_->GetStatsReport();
+
+  std::string remote_inbound_rtp_id =
+      "RTCRemoteInboundRtp" + MediaTypeUpperCase() + "Stream_8_12";
+  ASSERT_TRUE(report->Get(remote_inbound_rtp_id));
+  auto& remote_inbound_rtp = report->Get(remote_inbound_rtp_id)
+                                 ->cast_to<RTCRemoteInboundRtpStreamStats>();
+
+  EXPECT_TRUE(remote_inbound_rtp.transport_id.is_defined());
+  EXPECT_EQ("RTCTransport_TransportName_2",  // 2 for RTCP
+            *remote_inbound_rtp.transport_id);
+  EXPECT_TRUE(report->Get(*remote_inbound_rtp.transport_id));
+}
+
+INSTANTIATE_TEST_SUITE_P(,
+                         RTCStatsCollectorTestWithParamKind,
+                         ::testing::Values(cricket::MEDIA_TYPE_AUDIO,    // "/0"
+                                           cricket::MEDIA_TYPE_VIDEO));  // "/1"
+
 TEST_F(RTCStatsCollectorTest,
        RTCVideoSourceStatsNotCollectedForSenderWithoutTrack) {
   const uint32_t kSsrc = 4;