Add decoder-timing stats to VideoReceiveStream.

Also breaks out SsrcStats from VideoReceiveStream::Stats as they don't
have that much overlap.

R=mflodman@webrtc.org, stefan@webrtc.org
BUG=1667, 1788

Review URL: https://webrtc-codereview.appspot.com/40819004

Cr-Commit-Position: refs/heads/master@{#8501}
git-svn-id: http://webrtc.googlecode.com/svn/trunk@8501 4adac7df-926f-26a2-2b94-8c16560cd09d
diff --git a/talk/media/webrtc/webrtcvideoengine2.cc b/talk/media/webrtc/webrtcvideoengine2.cc
index cbd6eea..f2643c3 100644
--- a/talk/media/webrtc/webrtcvideoengine2.cc
+++ b/talk/media/webrtc/webrtcvideoengine2.cc
@@ -1766,21 +1766,20 @@
 
   info.send_frame_width = 0;
   info.send_frame_height = 0;
-  for (std::map<uint32_t, webrtc::SsrcStats>::iterator it =
+  for (std::map<uint32_t, webrtc::VideoSendStream::StreamStats>::iterator it =
            stats.substreams.begin();
-       it != stats.substreams.end();
-       ++it) {
+       it != stats.substreams.end(); ++it) {
     // TODO(pbos): Wire up additional stats, such as padding bytes.
-    webrtc::SsrcStats stream_stats = it->second;
+    webrtc::VideoSendStream::StreamStats stream_stats = it->second;
     info.bytes_sent += stream_stats.rtp_stats.transmitted.payload_bytes +
                        stream_stats.rtp_stats.transmitted.header_bytes +
                        stream_stats.rtp_stats.transmitted.padding_bytes;
     info.packets_sent += stream_stats.rtp_stats.transmitted.packets;
     info.packets_lost += stream_stats.rtcp_stats.cumulative_lost;
-    if (stream_stats.sent_width > info.send_frame_width)
-      info.send_frame_width = stream_stats.sent_width;
-    if (stream_stats.sent_height > info.send_frame_height)
-      info.send_frame_height = stream_stats.sent_height;
+    if (stream_stats.width > info.send_frame_width)
+      info.send_frame_width = stream_stats.width;
+    if (stream_stats.height > info.send_frame_height)
+      info.send_frame_height = stream_stats.height;
     info.firs_rcvd += stream_stats.rtcp_packet_type_counts.fir_packets;
     info.nacks_rcvd += stream_stats.rtcp_packet_type_counts.nack_packets;
     info.plis_rcvd += stream_stats.rtcp_packet_type_counts.pli_packets;
@@ -1788,7 +1787,8 @@
 
   if (!stats.substreams.empty()) {
     // TODO(pbos): Report fraction lost per SSRC.
-    webrtc::SsrcStats first_stream_stats = stats.substreams.begin()->second;
+    webrtc::VideoSendStream::StreamStats first_stream_stats =
+        stats.substreams.begin()->second;
     info.fraction_lost =
         static_cast<float>(first_stream_stats.rtcp_stats.fraction_lost) /
         (1 << 8);
@@ -1804,10 +1804,9 @@
     return;
   }
   webrtc::VideoSendStream::Stats stats = stream_->GetStats();
-  for (std::map<uint32_t, webrtc::SsrcStats>::iterator it =
+  for (std::map<uint32_t, webrtc::VideoSendStream::StreamStats>::iterator it =
            stats.substreams.begin();
-       it != stats.substreams.end();
-       ++it) {
+       it != stats.substreams.end(); ++it) {
     bwe_info->transmit_bitrate += it->second.total_bitrate_bps;
     bwe_info->retransmit_bitrate += it->second.retransmit_bitrate_bps;
   }
@@ -2043,6 +2042,14 @@
     info.capture_start_ntp_time_ms = estimated_remote_start_ntp_time_ms_;
   }
 
+  info.decode_ms = stats.decode_ms;
+  info.max_decode_ms = stats.max_decode_ms;
+  info.current_delay_ms = stats.current_delay_ms;
+  info.target_delay_ms = stats.target_delay_ms;
+  info.jitter_buffer_ms = stats.jitter_buffer_ms;
+  info.min_playout_delay_ms = stats.min_playout_delay_ms;
+  info.render_delay_ms = stats.render_delay_ms;
+
   info.firs_sent = stats.rtcp_packet_type_counts.fir_packets;
   info.plis_sent = stats.rtcp_packet_type_counts.pli_packets;
   info.nacks_sent = stats.rtcp_packet_type_counts.nack_packets;
diff --git a/talk/media/webrtc/webrtcvideoengine2_unittest.cc b/talk/media/webrtc/webrtcvideoengine2_unittest.cc
index deb0e29..b4f58e2 100644
--- a/talk/media/webrtc/webrtcvideoengine2_unittest.cc
+++ b/talk/media/webrtc/webrtcvideoengine2_unittest.cc
@@ -2041,12 +2041,12 @@
 TEST_F(WebRtcVideoChannel2Test, GetStatsReportsUpperResolution) {
   FakeVideoSendStream* stream = AddSendStream();
   webrtc::VideoSendStream::Stats stats;
-  stats.substreams[17].sent_width = 123;
-  stats.substreams[17].sent_height = 40;
-  stats.substreams[42].sent_width = 80;
-  stats.substreams[42].sent_height = 31;
-  stats.substreams[11].sent_width = 20;
-  stats.substreams[11].sent_height = 90;
+  stats.substreams[17].width = 123;
+  stats.substreams[17].height = 40;
+  stats.substreams[42].width = 80;
+  stats.substreams[42].height = 31;
+  stats.substreams[11].width = 20;
+  stats.substreams[11].height = 90;
   stream->SetStats(stats);
 
   cricket::VideoMediaInfo info;
@@ -2096,6 +2096,29 @@
             info.receivers[0].plis_sent);
 }
 
+TEST_F(WebRtcVideoChannel2Test, GetStatsTranslatesDecodeStatsCorrectly) {
+  FakeVideoReceiveStream* stream = AddRecvStream();
+  webrtc::VideoReceiveStream::Stats stats;
+  stats.decode_ms = 2;
+  stats.max_decode_ms = 3;
+  stats.current_delay_ms = 4;
+  stats.target_delay_ms = 5;
+  stats.jitter_buffer_ms = 6;
+  stats.min_playout_delay_ms = 7;
+  stats.render_delay_ms = 8;
+  stream->SetStats(stats);
+
+  cricket::VideoMediaInfo info;
+  ASSERT_TRUE(channel_->GetStats(cricket::StatsOptions(), &info));
+  EXPECT_EQ(stats.decode_ms, info.receivers[0].decode_ms);
+  EXPECT_EQ(stats.max_decode_ms, info.receivers[0].max_decode_ms);
+  EXPECT_EQ(stats.current_delay_ms, info.receivers[0].current_delay_ms);
+  EXPECT_EQ(stats.target_delay_ms, info.receivers[0].target_delay_ms);
+  EXPECT_EQ(stats.jitter_buffer_ms, info.receivers[0].jitter_buffer_ms);
+  EXPECT_EQ(stats.min_playout_delay_ms, info.receivers[0].min_playout_delay_ms);
+  EXPECT_EQ(stats.render_delay_ms, info.receivers[0].render_delay_ms);
+}
+
 TEST_F(WebRtcVideoChannel2Test, TranslatesCallStatsCorrectly) {
   AddSendStream();
   AddSendStream();
diff --git a/webrtc/config.h b/webrtc/config.h
index c699170..9f2a7a3 100644
--- a/webrtc/config.h
+++ b/webrtc/config.h
@@ -21,27 +21,6 @@
 
 namespace webrtc {
 
-struct SsrcStats {
-  SsrcStats()
-      : sent_width(0),
-        sent_height(0),
-        total_bitrate_bps(0),
-        retransmit_bitrate_bps(0),
-        avg_delay_ms(0),
-        max_delay_ms(0) {}
-  FrameCounts frame_counts;
-  int sent_width;
-  int sent_height;
-  // TODO(holmer): Move bitrate_bps out to the webrtc::Call layer.
-  int total_bitrate_bps;
-  int retransmit_bitrate_bps;
-  int avg_delay_ms;
-  int max_delay_ms;
-  StreamDataCounters rtp_stats;
-  RtcpPacketTypeCounter rtcp_packet_type_counts;
-  RtcpStatistics rtcp_stats;
-};
-
 // Settings for NACK, see RFC 4585 for details.
 struct NackConfig {
   NackConfig() : rtp_history_ms(0) {}
diff --git a/webrtc/video/end_to_end_tests.cc b/webrtc/video/end_to_end_tests.cc
index 7b349a9..66cd74f 100644
--- a/webrtc/video/end_to_end_tests.cc
+++ b/webrtc/video/end_to_end_tests.cc
@@ -1630,7 +1630,7 @@
             stats.rtp_stats.retransmitted.packets != 0;
 
         receive_stats_filled_["CodecStats"] |=
-            stats.avg_delay_ms != 0 || stats.discarded_packets != 0;
+            stats.target_delay_ms != 0 || stats.discarded_packets != 0;
 
         receive_stats_filled_["FrameCounts"] |=
             stats.frame_counts.key_frames != 0 ||
@@ -1656,17 +1656,16 @@
       send_stats_filled_["NumStreams"] |=
           stats.substreams.size() == expected_send_ssrcs_.size();
 
-      for (std::map<uint32_t, SsrcStats>::const_iterator it =
+      for (std::map<uint32_t, VideoSendStream::StreamStats>::const_iterator it =
                stats.substreams.begin();
-           it != stats.substreams.end();
-           ++it) {
+           it != stats.substreams.end(); ++it) {
         EXPECT_TRUE(expected_send_ssrcs_.find(it->first) !=
                     expected_send_ssrcs_.end());
 
         send_stats_filled_[CompoundKey("CapturedFrameRate", it->first)] |=
             stats.input_frame_rate != 0;
 
-        const SsrcStats& stream_stats = it->second;
+        const VideoSendStream::StreamStats& stream_stats = it->second;
 
         send_stats_filled_[CompoundKey("StatisticsUpdated", it->first)] |=
             stream_stats.rtcp_stats.cumulative_lost != 0 ||
diff --git a/webrtc/video/receive_statistics_proxy.cc b/webrtc/video/receive_statistics_proxy.cc
index 444f7c1..6e9505c 100644
--- a/webrtc/video/receive_statistics_proxy.cc
+++ b/webrtc/video/receive_statistics_proxy.cc
@@ -47,7 +47,13 @@
                                            int min_playout_delay_ms,
                                            int render_delay_ms) {
   CriticalSectionScoped lock(crit_.get());
-  stats_.avg_delay_ms = target_delay_ms;
+  stats_.decode_ms = decode_ms;
+  stats_.max_decode_ms = max_decode_ms;
+  stats_.current_delay_ms = current_delay_ms;
+  stats_.target_delay_ms = target_delay_ms;
+  stats_.jitter_buffer_ms = jitter_buffer_ms;
+  stats_.min_playout_delay_ms = min_playout_delay_ms;
+  stats_.render_delay_ms = render_delay_ms;
 }
 
 void ReceiveStatisticsProxy::RtcpPacketTypesCounterUpdated(
diff --git a/webrtc/video/send_statistics_proxy.cc b/webrtc/video/send_statistics_proxy.cc
index 00a1f0d..64126d2 100644
--- a/webrtc/video/send_statistics_proxy.cc
+++ b/webrtc/video/send_statistics_proxy.cc
@@ -57,20 +57,23 @@
 
 void SendStatisticsProxy::PurgeOldStats() {
   int64_t current_time_ms = clock_->TimeInMilliseconds();
-  for (std::map<uint32_t, SsrcStats>::iterator it = stats_.substreams.begin();
+  for (std::map<uint32_t, VideoSendStream::StreamStats>::iterator it =
+           stats_.substreams.begin();
        it != stats_.substreams.end(); ++it) {
     uint32_t ssrc = it->first;
     if (update_times_[ssrc].resolution_update_ms + kStatsTimeoutMs >
         current_time_ms)
       continue;
 
-    it->second.sent_width = 0;
-    it->second.sent_height = 0;
+    it->second.width = 0;
+    it->second.height = 0;
   }
 }
 
-SsrcStats* SendStatisticsProxy::GetStatsEntry(uint32_t ssrc) {
-  std::map<uint32_t, SsrcStats>::iterator it = stats_.substreams.find(ssrc);
+VideoSendStream::StreamStats* SendStatisticsProxy::GetStatsEntry(
+    uint32_t ssrc) {
+  std::map<uint32_t, VideoSendStream::StreamStats>::iterator it =
+      stats_.substreams.find(ssrc);
   if (it != stats_.substreams.end())
     return &it->second;
 
@@ -98,12 +101,12 @@
   uint32_t ssrc = config_.rtp.ssrcs[simulcast_idx];
 
   CriticalSectionScoped lock(crit_.get());
-  SsrcStats* stats = GetStatsEntry(ssrc);
+  VideoSendStream::StreamStats* stats = GetStatsEntry(ssrc);
   if (stats == NULL)
     return;
 
-  stats->sent_width = encoded_image._encodedWidth;
-  stats->sent_height = encoded_image._encodedHeight;
+  stats->width = encoded_image._encodedWidth;
+  stats->height = encoded_image._encodedHeight;
   update_times_[ssrc].resolution_update_ms = clock_->TimeInMilliseconds();
 }
 
@@ -111,7 +114,7 @@
     uint32_t ssrc,
     const RtcpPacketTypeCounter& packet_counter) {
   CriticalSectionScoped lock(crit_.get());
-  SsrcStats* stats = GetStatsEntry(ssrc);
+  VideoSendStream::StreamStats* stats = GetStatsEntry(ssrc);
   if (stats == NULL)
     return;
 
@@ -121,7 +124,7 @@
 void SendStatisticsProxy::StatisticsUpdated(const RtcpStatistics& statistics,
                                             uint32_t ssrc) {
   CriticalSectionScoped lock(crit_.get());
-  SsrcStats* stats = GetStatsEntry(ssrc);
+  VideoSendStream::StreamStats* stats = GetStatsEntry(ssrc);
   if (stats == NULL)
     return;
 
@@ -135,11 +138,9 @@
     const StreamDataCounters& counters,
     uint32_t ssrc) {
   CriticalSectionScoped lock(crit_.get());
-  SsrcStats* stats = GetStatsEntry(ssrc);
+  VideoSendStream::StreamStats* stats = GetStatsEntry(ssrc);
   DCHECK(stats != NULL) << "DataCountersUpdated reported for unknown ssrc: "
                         << ssrc;
-  if (stats == NULL)
-    return;
 
   stats->rtp_stats = counters;
 }
@@ -148,7 +149,7 @@
                                  const BitrateStatistics& retransmit_stats,
                                  uint32_t ssrc) {
   CriticalSectionScoped lock(crit_.get());
-  SsrcStats* stats = GetStatsEntry(ssrc);
+  VideoSendStream::StreamStats* stats = GetStatsEntry(ssrc);
   if (stats == NULL)
     return;
 
@@ -159,7 +160,7 @@
 void SendStatisticsProxy::FrameCountUpdated(const FrameCounts& frame_counts,
                                             uint32_t ssrc) {
   CriticalSectionScoped lock(crit_.get());
-  SsrcStats* stats = GetStatsEntry(ssrc);
+  VideoSendStream::StreamStats* stats = GetStatsEntry(ssrc);
   if (stats == NULL)
     return;
 
@@ -170,7 +171,7 @@
                                                int max_delay_ms,
                                                uint32_t ssrc) {
   CriticalSectionScoped lock(crit_.get());
-  SsrcStats* stats = GetStatsEntry(ssrc);
+  VideoSendStream::StreamStats* stats = GetStatsEntry(ssrc);
   if (stats == NULL)
     return;
   stats->avg_delay_ms = avg_delay_ms;
diff --git a/webrtc/video/send_statistics_proxy.h b/webrtc/video/send_statistics_proxy.h
index 568ffc4..5d4edcd 100644
--- a/webrtc/video/send_statistics_proxy.h
+++ b/webrtc/video/send_statistics_proxy.h
@@ -94,7 +94,8 @@
     int64_t resolution_update_ms;
   };
   void PurgeOldStats() EXCLUSIVE_LOCKS_REQUIRED(crit_);
-  SsrcStats* GetStatsEntry(uint32_t ssrc) EXCLUSIVE_LOCKS_REQUIRED(crit_);
+  VideoSendStream::StreamStats* GetStatsEntry(uint32_t ssrc)
+      EXCLUSIVE_LOCKS_REQUIRED(crit_);
 
   Clock* const clock_;
   const VideoSendStream::Config config_;
diff --git a/webrtc/video/send_statistics_proxy_unittest.cc b/webrtc/video/send_statistics_proxy_unittest.cc
index 2a154f3..ffbdc6e 100644
--- a/webrtc/video/send_statistics_proxy_unittest.cc
+++ b/webrtc/video/send_statistics_proxy_unittest.cc
@@ -49,15 +49,14 @@
     EXPECT_EQ(one.suspended, other.suspended);
 
     EXPECT_EQ(one.substreams.size(), other.substreams.size());
-    for (std::map<uint32_t, SsrcStats>::const_iterator it =
+    for (std::map<uint32_t, VideoSendStream::StreamStats>::const_iterator it =
              one.substreams.begin();
-         it != one.substreams.end();
-         ++it) {
-      std::map<uint32_t, SsrcStats>::const_iterator corresponding_it =
-          other.substreams.find(it->first);
+         it != one.substreams.end(); ++it) {
+      std::map<uint32_t, VideoSendStream::StreamStats>::const_iterator
+          corresponding_it = other.substreams.find(it->first);
       ASSERT_TRUE(corresponding_it != other.substreams.end());
-      const SsrcStats& a = it->second;
-      const SsrcStats& b = corresponding_it->second;
+      const VideoSendStream::StreamStats& a = it->second;
+      const VideoSendStream::StreamStats& b = corresponding_it->second;
 
       EXPECT_EQ(a.frame_counts.key_frames, b.frame_counts.key_frames);
       EXPECT_EQ(a.frame_counts.delta_frames, b.frame_counts.delta_frames);
@@ -91,7 +90,8 @@
   int avg_delay_ms_;
   int max_delay_ms_;
   VideoSendStream::Stats expected_;
-  typedef std::map<uint32_t, SsrcStats>::const_iterator StreamIterator;
+  typedef std::map<uint32_t, VideoSendStream::StreamStats>::const_iterator
+      StreamIterator;
 };
 
 TEST_F(SendStatisticsProxyTest, RtcpStatistics) {
@@ -100,7 +100,7 @@
        it != config_.rtp.ssrcs.end();
        ++it) {
     const uint32_t ssrc = *it;
-    SsrcStats& ssrc_stats = expected_.substreams[ssrc];
+    VideoSendStream::StreamStats& ssrc_stats = expected_.substreams[ssrc];
 
     // Add statistics with some arbitrary, but unique, numbers.
     uint32_t offset = ssrc * sizeof(RtcpStatistics);
@@ -114,7 +114,7 @@
        it != config_.rtp.rtx.ssrcs.end();
        ++it) {
     const uint32_t ssrc = *it;
-    SsrcStats& ssrc_stats = expected_.substreams[ssrc];
+    VideoSendStream::StreamStats& ssrc_stats = expected_.substreams[ssrc];
 
     // Add statistics with some arbitrary, but unique, numbers.
     uint32_t offset = ssrc * sizeof(RtcpStatistics);
@@ -171,8 +171,8 @@
        ++it) {
     const uint32_t ssrc = *it;
     // Add statistics with some arbitrary, but unique, numbers.
-    SsrcStats& stats = expected_.substreams[ssrc];
-    uint32_t offset = ssrc * sizeof(SsrcStats);
+    VideoSendStream::StreamStats& stats = expected_.substreams[ssrc];
+    uint32_t offset = ssrc * sizeof(VideoSendStream::StreamStats);
     FrameCounts frame_counts;
     frame_counts.key_frames = offset;
     frame_counts.delta_frames = offset + 1;
@@ -184,8 +184,8 @@
        ++it) {
     const uint32_t ssrc = *it;
     // Add statistics with some arbitrary, but unique, numbers.
-    SsrcStats& stats = expected_.substreams[ssrc];
-    uint32_t offset = ssrc * sizeof(SsrcStats);
+    VideoSendStream::StreamStats& stats = expected_.substreams[ssrc];
+    uint32_t offset = ssrc * sizeof(VideoSendStream::StreamStats);
     FrameCounts frame_counts;
     frame_counts.key_frames = offset;
     frame_counts.delta_frames = offset + 1;
@@ -342,16 +342,16 @@
   statistics_proxy_->OnSendEncodedImage(encoded_image, &rtp_video_header);
 
   VideoSendStream::Stats stats = statistics_proxy_->GetStats();
-  EXPECT_EQ(kEncodedWidth, stats.substreams[config_.rtp.ssrcs[0]].sent_width);
-  EXPECT_EQ(kEncodedHeight, stats.substreams[config_.rtp.ssrcs[0]].sent_height);
-  EXPECT_EQ(kEncodedWidth, stats.substreams[config_.rtp.ssrcs[1]].sent_width);
-  EXPECT_EQ(kEncodedHeight, stats.substreams[config_.rtp.ssrcs[1]].sent_height);
+  EXPECT_EQ(kEncodedWidth, stats.substreams[config_.rtp.ssrcs[0]].width);
+  EXPECT_EQ(kEncodedHeight, stats.substreams[config_.rtp.ssrcs[0]].height);
+  EXPECT_EQ(kEncodedWidth, stats.substreams[config_.rtp.ssrcs[1]].width);
+  EXPECT_EQ(kEncodedHeight, stats.substreams[config_.rtp.ssrcs[1]].height);
 
   // Forward almost to timeout, this should not have removed stats.
   fake_clock_.AdvanceTimeMilliseconds(SendStatisticsProxy::kStatsTimeoutMs - 1);
   stats = statistics_proxy_->GetStats();
-  EXPECT_EQ(kEncodedWidth, stats.substreams[config_.rtp.ssrcs[0]].sent_width);
-  EXPECT_EQ(kEncodedHeight, stats.substreams[config_.rtp.ssrcs[0]].sent_height);
+  EXPECT_EQ(kEncodedWidth, stats.substreams[config_.rtp.ssrcs[0]].width);
+  EXPECT_EQ(kEncodedHeight, stats.substreams[config_.rtp.ssrcs[0]].height);
 
   // Update the first SSRC with bogus RTCP stats to make sure that encoded
   // resolution still times out (no global timeout for all stats).
@@ -368,10 +368,10 @@
   // reported, but substream 1 should.
   fake_clock_.AdvanceTimeMilliseconds(1);
   stats = statistics_proxy_->GetStats();
-  EXPECT_EQ(0, stats.substreams[config_.rtp.ssrcs[0]].sent_width);
-  EXPECT_EQ(0, stats.substreams[config_.rtp.ssrcs[0]].sent_height);
-  EXPECT_EQ(kEncodedWidth, stats.substreams[config_.rtp.ssrcs[1]].sent_width);
-  EXPECT_EQ(kEncodedHeight, stats.substreams[config_.rtp.ssrcs[1]].sent_height);
+  EXPECT_EQ(0, stats.substreams[config_.rtp.ssrcs[0]].width);
+  EXPECT_EQ(0, stats.substreams[config_.rtp.ssrcs[0]].height);
+  EXPECT_EQ(kEncodedWidth, stats.substreams[config_.rtp.ssrcs[1]].width);
+  EXPECT_EQ(kEncodedHeight, stats.substreams[config_.rtp.ssrcs[1]].height);
 }
 
 }  // namespace webrtc
diff --git a/webrtc/video/video_send_stream_tests.cc b/webrtc/video/video_send_stream_tests.cc
index f5ec59b..e9ae9a7 100644
--- a/webrtc/video/video_send_stream_tests.cc
+++ b/webrtc/video/video_send_stream_tests.cc
@@ -1673,9 +1673,10 @@
                     stats.substreams.end())
             << "No stats for SSRC: " << kSendSsrcs[i]
             << ", stats should exist as soon as frames have been encoded.";
-        SsrcStats ssrc_stats = stats.substreams[kSendSsrcs[i]];
-        EXPECT_EQ(kEncodedResolution[i].width, ssrc_stats.sent_width);
-        EXPECT_EQ(kEncodedResolution[i].height, ssrc_stats.sent_height);
+        VideoSendStream::StreamStats ssrc_stats =
+            stats.substreams[kSendSsrcs[i]];
+        EXPECT_EQ(kEncodedResolution[i].width, ssrc_stats.width);
+        EXPECT_EQ(kEncodedResolution[i].height, ssrc_stats.height);
       }
     }
 
diff --git a/webrtc/video_receive_stream.h b/webrtc/video_receive_stream.h
index 5722c33..0f2151d 100644
--- a/webrtc/video_receive_stream.h
+++ b/webrtc/video_receive_stream.h
@@ -64,22 +64,29 @@
     int expected_delay_ms;
   };
 
-  struct Stats : public SsrcStats {
-    Stats()
-        : network_frame_rate(0),
-          decode_frame_rate(0),
-          render_frame_rate(0),
-          avg_delay_ms(0),
-          discarded_packets(0),
-          ssrc(0) {}
+  struct Stats {
+    int network_frame_rate = 0;
+    int decode_frame_rate = 0;
+    int render_frame_rate = 0;
 
-    int network_frame_rate;
-    int decode_frame_rate;
-    int render_frame_rate;
-    int avg_delay_ms;
-    int discarded_packets;
-    uint32_t ssrc;
+    // Decoder stats.
+    FrameCounts frame_counts;
+    int decode_ms = 0;
+    int max_decode_ms = 0;
+    int current_delay_ms = 0;
+    int target_delay_ms = 0;
+    int jitter_buffer_ms = 0;
+    int min_playout_delay_ms = 0;
+    int render_delay_ms = 0;
+
+    int total_bitrate_bps = 0;
+    int discarded_packets = 0;
+
+    uint32_t ssrc = 0;
     std::string c_name;
+    StreamDataCounters rtp_stats;
+    RtcpPacketTypeCounter rtcp_packet_type_counts;
+    RtcpStatistics rtcp_stats;
   };
 
   struct Config {
diff --git a/webrtc/video_send_stream.h b/webrtc/video_send_stream.h
index 7483ceb..0e41cc5 100644
--- a/webrtc/video_send_stream.h
+++ b/webrtc/video_send_stream.h
@@ -37,6 +37,20 @@
 
 class VideoSendStream {
  public:
+  struct StreamStats {
+    FrameCounts frame_counts;
+    int width = 0;
+    int height = 0;
+    // TODO(holmer): Move bitrate_bps out to the webrtc::Call layer.
+    int total_bitrate_bps = 0;
+    int retransmit_bitrate_bps = 0;
+    int avg_delay_ms = 0;
+    int max_delay_ms = 0;
+    StreamDataCounters rtp_stats;
+    RtcpPacketTypeCounter rtcp_packet_type_counts;
+    RtcpStatistics rtcp_stats;
+  };
+
   struct Stats {
     Stats()
         : input_frame_rate(0),
@@ -47,7 +61,7 @@
     int encode_frame_rate;
     int media_bitrate_bps;
     bool suspended;
-    std::map<uint32_t, SsrcStats> substreams;
+    std::map<uint32_t, StreamStats> substreams;
   };
 
   struct Config {