[Stats] Include RTX retransmissions in the VideoSenderInfo.

Ignoring retransmissions carried over the RTX stream was a bug. This CL
fixes the bug, so that all retransmissions are accounted for. It also
adds test coverage for this.

This resolves https://crbug.com/webrtc/11440 but does not resolve
https://crbug.com/webrtc/11439.

Bug: webrtc:11440, webrtc:11439
Change-Id: Ifb10aa60a0f453738aaa30de90eaa5b31f9ec265
Reviewed-on: https://webrtc-review.googlesource.com/c/src/+/170639
Reviewed-by: Ilya Nikolaevskiy <ilnik@webrtc.org>
Commit-Queue: Henrik Boström <hbos@webrtc.org>
Cr-Commit-Position: refs/heads/master@{#30822}
diff --git a/media/engine/webrtc_video_engine.cc b/media/engine/webrtc_video_engine.cc
index 2c6067e..434a758 100644
--- a/media/engine/webrtc_video_engine.cc
+++ b/media/engine/webrtc_video_engine.cc
@@ -2431,9 +2431,16 @@
         stream_stats.rtp_stats.transmitted.padding_bytes;
     info.packets_sent += stream_stats.rtp_stats.transmitted.packets;
     info.total_packet_send_delay_ms += stream_stats.total_packet_send_delay_ms;
-    // TODO(https://crbug.com/webrtc/10555): RTX retransmissions should show up
-    // in separate outbound-rtp stream objects.
-    if (!stream_stats.is_rtx && !stream_stats.is_flexfec) {
+    if (!stream_stats.is_flexfec) {
+      // Retransmissions can happen over the same SSRC that media is sent over,
+      // or a separate RTX stream is negotiated per SSRC, in which case there
+      // will be a |stream_stats| with "is_rtx == true". Since we are currently
+      // aggregating all substreams' counters into a single "info" we do not
+      // need to know the relationship between RTX streams and RTP streams here.
+      // TODO(https://crbug.com/webrtc/11439): To unblock simulcast-aware stats,
+      // where substreams are not aggregated, we need to know the relationship
+      // between RTX streams and RTP streams so that the correct "info" object
+      // accounts for the correct RTX retransmissions.
       info.retransmitted_bytes_sent +=
           stream_stats.rtp_stats.retransmitted.payload_bytes;
       info.retransmitted_packets_sent +=
diff --git a/media/engine/webrtc_video_engine_unittest.cc b/media/engine/webrtc_video_engine_unittest.cc
index 2fdfb04..563e3f3 100644
--- a/media/engine/webrtc_video_engine_unittest.cc
+++ b/media/engine/webrtc_video_engine_unittest.cc
@@ -5270,6 +5270,65 @@
 }
 
 TEST_F(WebRtcVideoChannelTest,
+       GetStatsReportsTransmittedAndRetransmittedBytesAndPacketsCorrectly) {
+  FakeVideoSendStream* stream = AddSendStream();
+  webrtc::VideoSendStream::Stats stats;
+  // Simulcast layer 1, RTP stream. header+padding=10, payload=20, packets=3.
+  stats.substreams[101].is_rtx = false;
+  stats.substreams[101].rtp_stats.transmitted.header_bytes = 5;
+  stats.substreams[101].rtp_stats.transmitted.padding_bytes = 5;
+  stats.substreams[101].rtp_stats.transmitted.payload_bytes = 20;
+  stats.substreams[101].rtp_stats.transmitted.packets = 3;
+  stats.substreams[101].rtp_stats.retransmitted.header_bytes = 0;
+  stats.substreams[101].rtp_stats.retransmitted.padding_bytes = 0;
+  stats.substreams[101].rtp_stats.retransmitted.payload_bytes = 0;
+  stats.substreams[101].rtp_stats.retransmitted.packets = 0;
+  // Simulcast layer 1, RTX stream. header+padding=5, payload=10, packets=1.
+  stats.substreams[102].is_rtx = true;
+  stats.substreams[102].rtp_stats.retransmitted.header_bytes = 3;
+  stats.substreams[102].rtp_stats.retransmitted.padding_bytes = 2;
+  stats.substreams[102].rtp_stats.retransmitted.payload_bytes = 10;
+  stats.substreams[102].rtp_stats.retransmitted.packets = 1;
+  stats.substreams[102].rtp_stats.transmitted =
+      stats.substreams[102].rtp_stats.retransmitted;
+  // Simulcast layer 2, RTP stream. header+padding=20, payload=40, packets=7.
+  stats.substreams[201].is_rtx = false;
+  stats.substreams[201].rtp_stats.transmitted.header_bytes = 10;
+  stats.substreams[201].rtp_stats.transmitted.padding_bytes = 10;
+  stats.substreams[201].rtp_stats.transmitted.payload_bytes = 40;
+  stats.substreams[201].rtp_stats.transmitted.packets = 7;
+  stats.substreams[201].rtp_stats.retransmitted.header_bytes = 0;
+  stats.substreams[201].rtp_stats.retransmitted.padding_bytes = 0;
+  stats.substreams[201].rtp_stats.retransmitted.payload_bytes = 0;
+  stats.substreams[201].rtp_stats.retransmitted.packets = 0;
+  // Simulcast layer 2, RTX stream. header+padding=10, payload=20, packets=4.
+  stats.substreams[202].is_rtx = true;
+  stats.substreams[202].rtp_stats.retransmitted.header_bytes = 6;
+  stats.substreams[202].rtp_stats.retransmitted.padding_bytes = 4;
+  stats.substreams[202].rtp_stats.retransmitted.payload_bytes = 20;
+  stats.substreams[202].rtp_stats.retransmitted.packets = 4;
+  stats.substreams[202].rtp_stats.transmitted =
+      stats.substreams[202].rtp_stats.retransmitted;
+  stream->SetStats(stats);
+
+  cricket::VideoMediaInfo info;
+  ASSERT_TRUE(channel_->GetStats(&info));
+  // TODO(https://crbug.com/webrtc/9547): Populate individual VideoSenderInfo
+  // objects for each simulcast stream, instead of accumulating all layers into
+  // a single VideoSenderInfo. When this is fixed, this test should expect that
+  // there are two VideoSenderInfo, where the first info accounts for the first
+  // RTX and the second info accounts for the second RTX. In order for the test
+  // to be set up correctly, it may need to be updated such that the
+  // relationship between RTP and RTX streams are known. See also
+  // https://crbug.com/webrtc/11439.
+  EXPECT_EQ(45u, info.senders[0].header_and_padding_bytes_sent);
+  EXPECT_EQ(90u, info.senders[0].payload_bytes_sent);
+  EXPECT_EQ(15, info.senders[0].packets_sent);
+  EXPECT_EQ(30u, info.senders[0].retransmitted_bytes_sent);
+  EXPECT_EQ(5u, info.senders[0].retransmitted_packets_sent);
+}
+
+TEST_F(WebRtcVideoChannelTest,
        GetStatsTranslatesBandwidthLimitedResolutionCorrectly) {
   FakeVideoSendStream* stream = AddSendStream();
   webrtc::VideoSendStream::Stats stats;