Add percentage of fec packets and recovered media packets to histogram stats:
- "WebRTC.Video.ReceivedFecPacketsInPercent"
- "WebRTC.Video.RecoveredMediaPacketsInPercentOfFec"

BUG=crbug/419657
R=stefan@webrtc.org

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

git-svn-id: http://webrtc.googlecode.com/svn/trunk@8072 4adac7df-926f-26a2-2b94-8c16560cd09d
diff --git a/webrtc/modules/rtp_rtcp/interface/fec_receiver.h b/webrtc/modules/rtp_rtcp/interface/fec_receiver.h
index da54bf6..3608165 100644
--- a/webrtc/modules/rtp_rtcp/interface/fec_receiver.h
+++ b/webrtc/modules/rtp_rtcp/interface/fec_receiver.h
@@ -16,6 +16,17 @@
 
 namespace webrtc {
 
+struct FecPacketCounter {
+  FecPacketCounter()
+      : num_packets(0),
+        num_fec_packets(0),
+        num_recovered_packets(0) {}
+
+  size_t num_packets;            // Number of received packets.
+  size_t num_fec_packets;        // Number of received FEC packets.
+  size_t num_recovered_packets;  // Number of recovered media packets using FEC.
+};
+
 class FecReceiver {
  public:
   static FecReceiver* Create(RtpData* callback);
@@ -28,6 +39,8 @@
                                        uint8_t ulpfec_payload_type) = 0;
 
   virtual int32_t ProcessReceivedFec() = 0;
+
+  virtual FecPacketCounter GetPacketCounter() const = 0;
 };
 }  // namespace webrtc
 #endif  // WEBRTC_MODULES_RTP_RTCP_INTERFACE_FEC_RECEIVER_H_
diff --git a/webrtc/modules/rtp_rtcp/source/fec_receiver_impl.cc b/webrtc/modules/rtp_rtcp/source/fec_receiver_impl.cc
index 0fcb6f7..c64a3c4 100644
--- a/webrtc/modules/rtp_rtcp/source/fec_receiver_impl.cc
+++ b/webrtc/modules/rtp_rtcp/source/fec_receiver_impl.cc
@@ -15,8 +15,8 @@
 #include "webrtc/modules/rtp_rtcp/source/rtp_receiver_video.h"
 #include "webrtc/modules/rtp_rtcp/source/rtp_utility.h"
 #include "webrtc/system_wrappers/interface/critical_section_wrapper.h"
-#include "webrtc/system_wrappers/interface/scoped_ptr.h"
 #include "webrtc/system_wrappers/interface/logging.h"
+#include "webrtc/system_wrappers/interface/scoped_ptr.h"
 
 // RFC 5109
 namespace webrtc {
@@ -41,6 +41,11 @@
   }
 }
 
+FecPacketCounter FecReceiverImpl::GetPacketCounter() const {
+  CriticalSectionScoped cs(crit_sect_.get());
+  return packet_counter_;
+}
+
 //     0                   1                    2                   3
 //     0 1 2 3 4 5 6 7 8 9 0 1 2 3  4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
 //    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
@@ -125,6 +130,7 @@
       return -1;
     }
   }
+  ++packet_counter_.num_packets;
 
   ForwardErrorCorrection::ReceivedPacket* second_received_packet = NULL;
   if (blockLength > 0) {
@@ -153,6 +159,7 @@
 
     second_received_packet->is_fec = true;
     second_received_packet->seq_num = header.sequenceNumber;
+    ++packet_counter_.num_fec_packets;
 
     // copy the FEC payload data
     memcpy(second_received_packet->pkt->data,
@@ -164,6 +171,7 @@
         payload_data_length - REDHeaderLength - blockLength;
 
   } else if (received_packet->is_fec) {
+    ++packet_counter_.num_fec_packets;
     // everything behind the RED header
     memcpy(
         received_packet->pkt->data,
@@ -233,6 +241,7 @@
     if ((*it)->returned)  // Already sent to the VCM and the jitter buffer.
       continue;
     ForwardErrorCorrection::Packet* packet = (*it)->pkt;
+    ++packet_counter_.num_recovered_packets;
     crit_sect_->Leave();
     if (!recovered_packet_callback_->OnRecoveredPacket(packet->data,
                                                        packet->length)) {
diff --git a/webrtc/modules/rtp_rtcp/source/fec_receiver_impl.h b/webrtc/modules/rtp_rtcp/source/fec_receiver_impl.h
index 8dd02b3..d8b9f42 100644
--- a/webrtc/modules/rtp_rtcp/source/fec_receiver_impl.h
+++ b/webrtc/modules/rtp_rtcp/source/fec_receiver_impl.h
@@ -35,6 +35,8 @@
 
   virtual int32_t ProcessReceivedFec() OVERRIDE;
 
+  virtual FecPacketCounter GetPacketCounter() const OVERRIDE;
+
  private:
   scoped_ptr<CriticalSectionWrapper> crit_sect_;
   RtpData* recovered_packet_callback_;
@@ -44,6 +46,7 @@
   // arrives. We should remove the list.
   ForwardErrorCorrection::ReceivedPacketList received_packet_list_;
   ForwardErrorCorrection::RecoveredPacketList recovered_packet_list_;
+  FecPacketCounter packet_counter_;
 };
 }  // namespace webrtc
 
diff --git a/webrtc/modules/rtp_rtcp/source/fec_receiver_unittest.cc b/webrtc/modules/rtp_rtcp/source/fec_receiver_unittest.cc
index 2a3b155..6c53a37 100644
--- a/webrtc/modules/rtp_rtcp/source/fec_receiver_unittest.cc
+++ b/webrtc/modules/rtp_rtcp/source/fec_receiver_unittest.cc
@@ -18,6 +18,7 @@
 #include "webrtc/modules/rtp_rtcp/mocks/mock_rtp_rtcp.h"
 #include "webrtc/modules/rtp_rtcp/source/fec_test_helper.h"
 #include "webrtc/modules/rtp_rtcp/source/forward_error_correction.h"
+#include "webrtc/system_wrappers/interface/scoped_ptr.h"
 
 using ::testing::_;
 using ::testing::Args;
@@ -29,15 +30,9 @@
 class ReceiverFecTest : public ::testing::Test {
  protected:
   virtual void SetUp() {
-    fec_ = new ForwardErrorCorrection();
-    receiver_fec_ = FecReceiver::Create(&rtp_data_callback_);
-    generator_ = new FrameGenerator();
-  }
-
-  virtual void TearDown() {
-    delete fec_;
-    delete receiver_fec_;
-    delete generator_;
+    fec_.reset(new ForwardErrorCorrection());
+    receiver_fec_.reset(FecReceiver::Create(&rtp_data_callback_));
+    generator_.reset(new FrameGenerator());
   }
 
   void GenerateFEC(std::list<Packet*>* media_packets,
@@ -86,10 +81,10 @@
     delete red_packet;
   }
 
-  ForwardErrorCorrection* fec_;
   MockRtpData rtp_data_callback_;
-  FecReceiver* receiver_fec_;
-  FrameGenerator* generator_;
+  scoped_ptr<ForwardErrorCorrection> fec_;
+  scoped_ptr<FecReceiver> receiver_fec_;
+  scoped_ptr<FrameGenerator> generator_;
 };
 
 void DeletePackets(std::list<Packet*>* packets) {
@@ -120,6 +115,11 @@
   VerifyReconstructedMediaPacket(*it, 1);
   EXPECT_EQ(0, receiver_fec_->ProcessReceivedFec());
 
+  FecPacketCounter counter = receiver_fec_->GetPacketCounter();
+  EXPECT_EQ(2U, counter.num_packets);
+  EXPECT_EQ(1U, counter.num_fec_packets);
+  EXPECT_EQ(1U, counter.num_recovered_packets);
+
   DeletePackets(&media_packets);
 }
 
diff --git a/webrtc/video_engine/vie_receiver.cc b/webrtc/video_engine/vie_receiver.cc
index 6adcffd..7e1034f 100644
--- a/webrtc/video_engine/vie_receiver.cc
+++ b/webrtc/video_engine/vie_receiver.cc
@@ -24,6 +24,7 @@
 #include "webrtc/modules/video_coding/main/interface/video_coding.h"
 #include "webrtc/system_wrappers/interface/critical_section_wrapper.h"
 #include "webrtc/system_wrappers/interface/logging.h"
+#include "webrtc/system_wrappers/interface/metrics.h"
 #include "webrtc/system_wrappers/interface/tick_util.h"
 #include "webrtc/system_wrappers/interface/timestamp_extrapolator.h"
 #include "webrtc/system_wrappers/interface/trace.h"
@@ -62,6 +63,7 @@
 }
 
 ViEReceiver::~ViEReceiver() {
+  UpdateHistograms();
   if (rtp_dump_) {
     rtp_dump_->Stop();
     RtpDump::DestroyRtpDump(rtp_dump_);
@@ -69,6 +71,19 @@
   }
 }
 
+void ViEReceiver::UpdateHistograms() {
+  FecPacketCounter counter = fec_receiver_->GetPacketCounter();
+  if (counter.num_packets > 0) {
+    RTC_HISTOGRAM_PERCENTAGE("WebRTC.Video.ReceivedFecPacketsInPercent",
+        counter.num_fec_packets * 100 / counter.num_packets);
+  }
+  if (counter.num_fec_packets > 0) {
+    RTC_HISTOGRAM_PERCENTAGE(
+        "WebRTC.Video.RecoveredMediaPacketsInPercentOfFec",
+            counter.num_recovered_packets * 100 / counter.num_fec_packets);
+  }
+}
+
 bool ViEReceiver::SetReceiveCodec(const VideoCodec& video_codec) {
   int8_t old_pltype = -1;
   if (rtp_payload_registry_->ReceivePayloadType(video_codec.plName,
diff --git a/webrtc/video_engine/vie_receiver.h b/webrtc/video_engine/vie_receiver.h
index 39a85e4..6354d68 100644
--- a/webrtc/video_engine/vie_receiver.h
+++ b/webrtc/video_engine/vie_receiver.h
@@ -104,6 +104,7 @@
   int InsertRTCPPacket(const uint8_t* rtcp_packet, size_t rtcp_packet_length);
   bool IsPacketInOrder(const RTPHeader& header) const;
   bool IsPacketRetransmitted(const RTPHeader& header, bool in_order) const;
+  void UpdateHistograms();
 
   scoped_ptr<CriticalSectionWrapper> receive_cs_;
   Clock* clock_;