Update StreamDataCounter with FEC bytes.

Add histograms stats for send/receive FEC bitrate:
- "WebRTC.Video.FecBitrateReceivedInKbps"
- "WebRTC.Video.FecBitrateSentInKbps"

Correct media payload bytes in StreamDataCounter to not include FEC bytes.

Fix stats for rtcp packets sent/received per minute (regression from r7910).

BUG=crbug/419657
R=holmer@google.com, mflodman@webrtc.org

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

git-svn-id: http://webrtc.googlecode.com/svn/trunk@8164 4adac7df-926f-26a2-2b94-8c16560cd09d
diff --git a/webrtc/common_types.h b/webrtc/common_types.h
index fe736cd..f347ec3 100644
--- a/webrtc/common_types.h
+++ b/webrtc/common_types.h
@@ -286,16 +286,16 @@
   }
 
   // Returns the number of bytes corresponding to the actual media payload (i.e.
-  // RTP headers, padding and retransmissions are excluded). Note this function
-  // does not have meaning for an RTX stream.
+  // RTP headers, padding, retransmissions and fec packets are excluded).
+  // Note this function does not have meaning for an RTX stream.
   size_t MediaPayloadBytes() const {
-    return transmitted.payload_bytes - retransmitted.payload_bytes;
+    return transmitted.payload_bytes - retransmitted.payload_bytes -
+           fec.payload_bytes;
   }
 
   int64_t first_packet_time_ms;  // Time when first packet is sent/received.
   RtpPacketCounter transmitted;  // Number of transmitted packets/bytes.
   RtpPacketCounter retransmitted;  // Number of retransmitted packets/bytes.
-  // TODO(asapersson): add FEC bytes.
   RtpPacketCounter fec;  // Number of redundancy packets/bytes.
 };
 
diff --git a/webrtc/modules/rtp_rtcp/interface/receive_statistics.h b/webrtc/modules/rtp_rtcp/interface/receive_statistics.h
index 701d8dd..3bd953f 100644
--- a/webrtc/modules/rtp_rtcp/interface/receive_statistics.h
+++ b/webrtc/modules/rtp_rtcp/interface/receive_statistics.h
@@ -61,7 +61,8 @@
                               bool retransmitted) = 0;
 
   // Increment counter for number of FEC packets received.
-  virtual void FecPacketReceived(uint32_t ssrc) = 0;
+  virtual void FecPacketReceived(const RTPHeader& header,
+                                 size_t packet_length) = 0;
 
   // Returns a map of all statisticians which have seen an incoming packet
   // during the last two seconds.
@@ -87,7 +88,8 @@
   virtual void IncomingPacket(const RTPHeader& rtp_header,
                               size_t packet_length,
                               bool retransmitted) OVERRIDE;
-  virtual void FecPacketReceived(uint32_t ssrc) OVERRIDE;
+  virtual void FecPacketReceived(const RTPHeader& header,
+                                 size_t packet_length) OVERRIDE;
   virtual StatisticianMap GetActiveStatisticians() const OVERRIDE;
   virtual StreamStatistician* GetStatistician(uint32_t ssrc) const OVERRIDE;
   virtual int64_t TimeUntilNextProcess() OVERRIDE;
diff --git a/webrtc/modules/rtp_rtcp/source/receive_statistics_impl.cc b/webrtc/modules/rtp_rtcp/source/receive_statistics_impl.cc
index aefab15..916ef54 100644
--- a/webrtc/modules/rtp_rtcp/source/receive_statistics_impl.cc
+++ b/webrtc/modules/rtp_rtcp/source/receive_statistics_impl.cc
@@ -200,10 +200,15 @@
   rtcp_callback_->StatisticsUpdated(data, ssrc);
 }
 
-void StreamStatisticianImpl::FecPacketReceived() {
+void StreamStatisticianImpl::FecPacketReceived(const RTPHeader& header,
+                                               size_t packet_length) {
   {
     CriticalSectionScoped cs(stream_lock_.get());
     ++receive_counters_.fec.packets;
+    receive_counters_.fec.payload_bytes +=
+        packet_length - (header.headerLength + header.paddingLength);
+    receive_counters_.fec.header_bytes += header.headerLength;
+    receive_counters_.fec.padding_bytes += header.paddingLength;
   }
   NotifyRtpCallback();
 }
@@ -441,12 +446,13 @@
   impl->IncomingPacket(header, packet_length, retransmitted);
 }
 
-void ReceiveStatisticsImpl::FecPacketReceived(uint32_t ssrc) {
+void ReceiveStatisticsImpl::FecPacketReceived(const RTPHeader& header,
+                                              size_t packet_length) {
   CriticalSectionScoped cs(receive_statistics_lock_.get());
-  StatisticianImplMap::iterator it = statisticians_.find(ssrc);
+  StatisticianImplMap::iterator it = statisticians_.find(header.ssrc);
   // Ignore FEC if it is the first packet.
   if (it != statisticians_.end()) {
-    it->second->FecPacketReceived();
+    it->second->FecPacketReceived(header, packet_length);
   }
 }
 
@@ -543,7 +549,8 @@
                                            size_t packet_length,
                                            bool retransmitted) {}
 
-void NullReceiveStatistics::FecPacketReceived(uint32_t ssrc) {}
+void NullReceiveStatistics::FecPacketReceived(const RTPHeader& header,
+                                              size_t packet_length) {}
 
 StatisticianMap NullReceiveStatistics::GetActiveStatisticians() const {
   return StatisticianMap();
diff --git a/webrtc/modules/rtp_rtcp/source/receive_statistics_impl.h b/webrtc/modules/rtp_rtcp/source/receive_statistics_impl.h
index 4b02f36..ab80a74 100644
--- a/webrtc/modules/rtp_rtcp/source/receive_statistics_impl.h
+++ b/webrtc/modules/rtp_rtcp/source/receive_statistics_impl.h
@@ -44,7 +44,7 @@
   void IncomingPacket(const RTPHeader& rtp_header,
                       size_t packet_length,
                       bool retransmitted);
-  void FecPacketReceived();
+  void FecPacketReceived(const RTPHeader& header, size_t packet_length);
   void SetMaxReorderingThreshold(int max_reordering_threshold);
   void ProcessBitrate();
   virtual void LastReceiveTimeNtp(uint32_t* secs, uint32_t* frac) const;
@@ -110,7 +110,8 @@
   virtual void IncomingPacket(const RTPHeader& header,
                               size_t packet_length,
                               bool retransmitted) OVERRIDE;
-  virtual void FecPacketReceived(uint32_t ssrc) OVERRIDE;
+  virtual void FecPacketReceived(const RTPHeader& header,
+                                 size_t packet_length) OVERRIDE;
   virtual StatisticianMap GetActiveStatisticians() const OVERRIDE;
   virtual StreamStatistician* GetStatistician(uint32_t ssrc) const OVERRIDE;
   virtual void SetMaxReorderingThreshold(int max_reordering_threshold) OVERRIDE;
diff --git a/webrtc/modules/rtp_rtcp/source/receive_statistics_unittest.cc b/webrtc/modules/rtp_rtcp/source/receive_statistics_unittest.cc
index c90e62e..7f3f564 100644
--- a/webrtc/modules/rtp_rtcp/source/receive_statistics_unittest.cc
+++ b/webrtc/modules/rtp_rtcp/source/receive_statistics_unittest.cc
@@ -276,6 +276,9 @@
     EXPECT_EQ(expected.retransmitted.padding_bytes,
               stats_.retransmitted.padding_bytes);
     EXPECT_EQ(expected.retransmitted.packets, stats_.retransmitted.packets);
+    EXPECT_EQ(expected.fec.payload_bytes, stats_.fec.payload_bytes);
+    EXPECT_EQ(expected.fec.header_bytes, stats_.fec.header_bytes);
+    EXPECT_EQ(expected.fec.padding_bytes, stats_.fec.padding_bytes);
     EXPECT_EQ(expected.fec.packets, stats_.fec.packets);
   }
 
@@ -336,13 +339,16 @@
   header1_.paddingLength = 0;
   ++header1_.sequenceNumber;
   clock_.AdvanceTimeMilliseconds(5);
-  // One recovered packet.
+  // One FEC packet.
   receive_statistics_->IncomingPacket(
       header1_, kPacketSize1 + kHeaderLength, false);
-  receive_statistics_->FecPacketReceived(kSsrc1);
+  receive_statistics_->FecPacketReceived(header1_,
+                                         kPacketSize1 + kHeaderLength);
   expected.transmitted.payload_bytes = kPacketSize1 * 4;
   expected.transmitted.header_bytes = kHeaderLength * 4;
   expected.transmitted.packets = 4;
+  expected.fec.payload_bytes = kPacketSize1;
+  expected.fec.header_bytes = kHeaderLength;
   expected.fec.packets = 1;
   callback.Matches(5, kSsrc1, expected);
 
@@ -361,12 +367,13 @@
   receive_statistics_->RegisterRtpStatisticsCallback(&callback);
 
   const uint32_t kHeaderLength = 20;
+  header1_.headerLength = kHeaderLength;
 
   // If first packet is FEC, ignore it.
-  receive_statistics_->FecPacketReceived(kSsrc1);
+  receive_statistics_->FecPacketReceived(header1_,
+                                         kPacketSize1 + kHeaderLength);
   EXPECT_EQ(0u, callback.num_calls_);
 
-  header1_.headerLength = kHeaderLength;
   receive_statistics_->IncomingPacket(
       header1_, kPacketSize1 + kHeaderLength, false);
   StreamDataCounters expected;
@@ -377,7 +384,10 @@
   expected.fec.packets = 0;
   callback.Matches(1, kSsrc1, expected);
 
-  receive_statistics_->FecPacketReceived(kSsrc1);
+  receive_statistics_->FecPacketReceived(header1_,
+                                         kPacketSize1 + kHeaderLength);
+  expected.fec.payload_bytes = kPacketSize1;
+  expected.fec.header_bytes = kHeaderLength;
   expected.fec.packets = 1;
   callback.Matches(2, kSsrc1, expected);
 }
diff --git a/webrtc/modules/rtp_rtcp/source/rtp_sender.cc b/webrtc/modules/rtp_rtcp/source/rtp_sender.cc
index 952e770..d7cc0bc 100644
--- a/webrtc/modules/rtp_rtcp/source/rtp_sender.cc
+++ b/webrtc/modules/rtp_rtcp/source/rtp_sender.cc
@@ -900,6 +900,10 @@
   }
   if (IsFecPacket(buffer, header)) {
     ++counters->fec.packets;
+    counters->fec.payload_bytes +=
+        packet_length - (header.headerLength + header.paddingLength);
+    counters->fec.header_bytes += header.headerLength;
+    counters->fec.padding_bytes += header.paddingLength;
   }
 
   if (is_retransmit) {
diff --git a/webrtc/video_engine/vie_channel.cc b/webrtc/video_engine/vie_channel.cc
index 1e0a056..1ec8a10 100644
--- a/webrtc/video_engine/vie_channel.cc
+++ b/webrtc/video_engine/vie_channel.cc
@@ -202,11 +202,11 @@
     int64_t elapsed_sec = rtcp_received.TimeSinceFirstPacketInMs(now) / 1000;
     if (elapsed_sec > metrics::kMinRunTimeInSeconds) {
       RTC_HISTOGRAM_COUNTS_10000("WebRTC.Video.NackPacketsReceivedPerMinute",
-          rtcp_received.nack_packets / elapsed_sec / 60);
+          rtcp_received.nack_packets * 60 / elapsed_sec);
       RTC_HISTOGRAM_COUNTS_10000("WebRTC.Video.FirPacketsReceivedPerMinute",
-          rtcp_received.fir_packets / elapsed_sec / 60);
+          rtcp_received.fir_packets * 60 / elapsed_sec);
       RTC_HISTOGRAM_COUNTS_10000("WebRTC.Video.PliPacketsReceivedPerMinute",
-          rtcp_received.pli_packets / elapsed_sec / 60);
+          rtcp_received.pli_packets * 60 / elapsed_sec);
       if (rtcp_received.nack_requests > 0) {
         RTC_HISTOGRAM_PERCENTAGE(
             "WebRTC.Video.UniqueNackRequestsReceivedInPercent",
@@ -224,11 +224,11 @@
     int64_t elapsed_sec = rtcp_sent.TimeSinceFirstPacketInMs(now) / 1000;
     if (elapsed_sec > metrics::kMinRunTimeInSeconds) {
       RTC_HISTOGRAM_COUNTS_10000("WebRTC.Video.NackPacketsSentPerMinute",
-          rtcp_sent.nack_packets / elapsed_sec / 60);
+          rtcp_sent.nack_packets * 60 / elapsed_sec);
       RTC_HISTOGRAM_COUNTS_10000("WebRTC.Video.FirPacketsSentPerMinute",
-          rtcp_sent.fir_packets / elapsed_sec / 60);
+          rtcp_sent.fir_packets * 60 / elapsed_sec);
       RTC_HISTOGRAM_COUNTS_10000("WebRTC.Video.PliPacketsSentPerMinute",
-          rtcp_sent.pli_packets / elapsed_sec / 60);
+          rtcp_sent.pli_packets * 60 / elapsed_sec);
       if (rtcp_sent.nack_requests > 0) {
         RTC_HISTOGRAM_PERCENTAGE("WebRTC.Video.UniqueNackRequestsSentInPercent",
             rtcp_sent.UniqueNackRequestsInPercent());
@@ -261,6 +261,10 @@
         RTC_HISTOGRAM_COUNTS_10000("WebRTC.Video.RtxBitrateReceivedInKbps",
             rtx.transmitted.TotalBytes() * 8 / elapsed_sec / 1000);
       }
+      if (vie_receiver_.IsFecEnabled()) {
+        RTC_HISTOGRAM_COUNTS_10000("WebRTC.Video.FecBitrateReceivedInKbps",
+            rtp_rtx.fec.TotalBytes() * 8 / elapsed_sec / 1000);
+      }
     }
   }
 }
@@ -290,6 +294,14 @@
     RTC_HISTOGRAM_COUNTS_10000("WebRTC.Video.RtxBitrateSentInKbps",
         rtx.transmitted.TotalBytes() * 8 / elapsed_sec / 1000);
   }
+  bool fec_enabled = false;
+  uint8_t pltype_red;
+  uint8_t pltype_fec;
+  rtp_rtcp_->GenericFECStatus(fec_enabled, pltype_red, pltype_fec);
+  if (fec_enabled) {
+    RTC_HISTOGRAM_COUNTS_10000("WebRTC.Video.FecBitrateSentInKbps",
+        rtp_rtx.fec.TotalBytes() * 8 / elapsed_sec / 1000);
+  }
 }
 
 int32_t ViEChannel::SetSendCodec(const VideoCodec& video_codec,
diff --git a/webrtc/video_engine/vie_receiver.cc b/webrtc/video_engine/vie_receiver.cc
index 7e1034f..cdff860 100644
--- a/webrtc/video_engine/vie_receiver.cc
+++ b/webrtc/video_engine/vie_receiver.cc
@@ -129,6 +129,10 @@
   return rtp_payload_registry_->GetRtxSsrc(ssrc);
 }
 
+bool ViEReceiver::IsFecEnabled() const {
+  return rtp_payload_registry_->ulpfec_payload_type() > -1;
+}
+
 uint32_t ViEReceiver::GetRemoteSsrc() const {
   return rtp_receiver_->SSRC();
 }
@@ -319,7 +323,7 @@
   if (rtp_payload_registry_->IsRed(header)) {
     int8_t ulpfec_pt = rtp_payload_registry_->ulpfec_payload_type();
     if (packet[header.headerLength] == ulpfec_pt)
-      rtp_receive_statistics_->FecPacketReceived(header.ssrc);
+      rtp_receive_statistics_->FecPacketReceived(header, packet_length);
     if (fec_receiver_->AddReceivedRedPacket(
             header, packet, packet_length, ulpfec_pt) != 0) {
       return false;
diff --git a/webrtc/video_engine/vie_receiver.h b/webrtc/video_engine/vie_receiver.h
index 6354d68..b8e6569 100644
--- a/webrtc/video_engine/vie_receiver.h
+++ b/webrtc/video_engine/vie_receiver.h
@@ -51,6 +51,8 @@
   void SetRtxSsrc(uint32_t ssrc);
   bool GetRtxSsrc(uint32_t* ssrc) const;
 
+  bool IsFecEnabled() const;
+
   uint32_t GetRemoteSsrc() const;
   int GetCsrcs(uint32_t* csrcs) const;