Add RTCP packet type counter (for getting statistics such as sent/received NACK and FIR).
Add counter to RTCP sender and RTCP receiver.
Add video api GetRtcpPacketTypes().

BUG=2638
R=mflodman@webrtc.org, stefan@webrtc.org

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

git-svn-id: http://webrtc.googlecode.com/svn/trunk@5575 4adac7df-926f-26a2-2b94-8c16560cd09d
diff --git a/webrtc/common_types.h b/webrtc/common_types.h
index 83201cf..9478a2d 100644
--- a/webrtc/common_types.h
+++ b/webrtc/common_types.h
@@ -192,6 +192,24 @@
                                  uint32_t ssrc) = 0;
 };
 
+// Statistics for RTCP packet types.
+struct RtcpPacketTypeCounter {
+  RtcpPacketTypeCounter()
+    : nack_packets(0),
+      fir_packets(0),
+      pli_packets(0) {}
+
+  void Add(const RtcpPacketTypeCounter& other) {
+    nack_packets += other.nack_packets;
+    fir_packets += other.fir_packets;
+    pli_packets += other.pli_packets;
+  }
+
+  uint32_t nack_packets;
+  uint32_t fir_packets;
+  uint32_t pli_packets;
+};
+
 // Data usage statistics for a (rtp) stream
 struct StreamDataCounters {
   StreamDataCounters()
diff --git a/webrtc/modules/rtp_rtcp/interface/rtp_rtcp.h b/webrtc/modules/rtp_rtcp/interface/rtp_rtcp.h
index 67dad0d..080aafd 100644
--- a/webrtc/modules/rtp_rtcp/interface/rtp_rtcp.h
+++ b/webrtc/modules/rtp_rtcp/interface/rtp_rtcp.h
@@ -508,6 +508,13 @@
     virtual int32_t RemoveRTCPReportBlock(const uint32_t SSRC) = 0;
 
     /*
+    *   Get number of sent and received RTCP packet types.
+    */
+    virtual void GetRtcpPacketTypeCounters(
+        RtcpPacketTypeCounter* packets_sent,
+        RtcpPacketTypeCounter* packets_received) const = 0;
+
+    /*
     *   (APP) Application specific data
     *
     *   return -1 on failure else 0
diff --git a/webrtc/modules/rtp_rtcp/mocks/mock_rtp_rtcp.h b/webrtc/modules/rtp_rtcp/mocks/mock_rtp_rtcp.h
index 42c7b4e..2215ac0 100644
--- a/webrtc/modules/rtp_rtcp/mocks/mock_rtp_rtcp.h
+++ b/webrtc/modules/rtp_rtcp/mocks/mock_rtp_rtcp.h
@@ -168,6 +168,8 @@
       int32_t(const uint32_t SSRC, const RTCPReportBlock* receiveBlock));
   MOCK_METHOD1(RemoveRTCPReportBlock,
       int32_t(const uint32_t SSRC));
+  MOCK_CONST_METHOD2(GetRtcpPacketTypeCounters,
+      void(RtcpPacketTypeCounter*, RtcpPacketTypeCounter*));
   MOCK_METHOD4(SetRTCPApplicationSpecificData,
       int32_t(const uint8_t subType, const uint32_t name, const uint8_t* data, const uint16_t length));
   MOCK_METHOD1(SetRTCPVoIPMetrics,
diff --git a/webrtc/modules/rtp_rtcp/source/rtcp_receiver.cc b/webrtc/modules/rtp_rtcp/source/rtcp_receiver.cc
index c9fb492..4012a81 100644
--- a/webrtc/modules/rtp_rtcp/source/rtcp_receiver.cc
+++ b/webrtc/modules/rtp_rtcp/source/rtcp_receiver.cc
@@ -317,6 +317,12 @@
   return 0;
 }
 
+void RTCPReceiver::GetPacketTypeCounter(
+    RtcpPacketTypeCounter* packet_counter) const {
+  CriticalSectionScoped lock(_criticalSectionRTCPReceiver);
+  *packet_counter = packet_type_counter_;
+}
+
 int32_t
 RTCPReceiver::IncomingRTCPPacket(RTCPPacketInformation& rtcpPacketInformation,
                                  RTCPUtility::RTCPParserV2* rtcpParser)
@@ -839,6 +845,10 @@
         HandleNACKItem(rtcpPacket, rtcpPacketInformation);
         pktType = rtcpParser.Iterate();
     }
+
+    if (rtcpPacketInformation.rtcpPacketTypeFlags & kRtcpNack) {
+      ++packet_type_counter_.nack_packets;
+    }
 }
 
 // no need for critsect we have _criticalSectionRTCPReceiver
@@ -1028,6 +1038,7 @@
   if (main_ssrc_ == rtcpPacket.PLI.MediaSSRC) {
     TRACE_EVENT_INSTANT0("webrtc_rtp", "PLI");
 
+    ++packet_type_counter_.pli_packets;
     // Received a signal that we need to send a new key frame.
     rtcpPacketInformation.rtcpPacketTypeFlags |= kRtcpPli;
   }
@@ -1270,6 +1281,9 @@
   if (main_ssrc_ != rtcpPacket.FIRItem.SSRC) {
     return;
   }
+
+  ++packet_type_counter_.fir_packets;
+
   // rtcpPacket.FIR.MediaSSRC SHOULD be 0 but we ignore to check it
   // we don't know who this originate from
   if (receiveInfo) {
diff --git a/webrtc/modules/rtp_rtcp/source/rtcp_receiver.h b/webrtc/modules/rtp_rtcp/source/rtcp_receiver.h
index 637773d..ebffb7c 100644
--- a/webrtc/modules/rtp_rtcp/source/rtcp_receiver.h
+++ b/webrtc/modules/rtp_rtcp/source/rtcp_receiver.h
@@ -88,6 +88,8 @@
     int32_t StatisticsReceived(
         std::vector<RTCPReportBlock>* receiveBlocks) const;
 
+    void GetPacketTypeCounter(RtcpPacketTypeCounter* packet_counter) const;
+
     // Returns true if we haven't received an RTCP RR for several RTCP
     // intervals, but only triggers true once.
     bool RtcpRrTimeout(int64_t rtcp_interval_ms);
@@ -266,6 +268,8 @@
   int64_t _lastIncreasedSequenceNumberMs;
 
   RtcpStatisticsCallback* stats_callback_;
+
+  RtcpPacketTypeCounter packet_type_counter_;
 };
 }  // namespace webrtc
 #endif // WEBRTC_MODULES_RTP_RTCP_SOURCE_RTCP_RECEIVER_H_
diff --git a/webrtc/modules/rtp_rtcp/source/rtcp_sender.cc b/webrtc/modules/rtp_rtcp/source/rtcp_sender.cc
index a376df7..f3c33bf 100644
--- a/webrtc/modules/rtp_rtcp/source/rtcp_sender.cc
+++ b/webrtc/modules/rtp_rtcp/source/rtcp_sender.cc
@@ -156,10 +156,7 @@
 
     xrSendReceiverReferenceTimeEnabled_(false),
     _xrSendVoIPMetric(false),
-    _xrVoIPMetric(),
-    _nackCount(0),
-    _pliCount(0),
-    _fullIntraRequestCount(0)
+    _xrVoIPMetric()
 {
     memset(_CNAME, 0, sizeof(_CNAME));
     memset(_lastSendReport, 0, sizeof(_lastSendReport));
@@ -239,10 +236,7 @@
     memset(_lastRTCPTime, 0, sizeof(_lastRTCPTime));
     last_xr_rr_.clear();
 
-    _nackCount = 0;
-    _pliCount = 0;
-    _fullIntraRequestCount = 0;
-
+    memset(&packet_type_counter_, 0, sizeof(packet_type_counter_));
     return 0;
 }
 
@@ -616,6 +610,12 @@
   return true;
 }
 
+void RTCPSender::GetPacketTypeCounter(
+    RtcpPacketTypeCounter* packet_counter) const {
+  CriticalSectionScoped lock(_criticalSectionRTCPSender);
+  *packet_counter = packet_type_counter_;
+}
+
 int32_t RTCPSender::AddExternalReportBlock(
     uint32_t SSRC,
     const RTCPReportBlock* reportBlock) {
@@ -1919,8 +1919,9 @@
         return position;
       }
       TRACE_EVENT_INSTANT0("webrtc_rtp", "RTCPSender::PLI");
-      _pliCount++;
-      TRACE_COUNTER_ID1("webrtc_rtp", "RTCP_PLICount", _SSRC, _pliCount);
+      ++packet_type_counter_.pli_packets;
+      TRACE_COUNTER_ID1("webrtc_rtp", "RTCP_PLICount", _SSRC,
+                        packet_type_counter_.pli_packets);
   }
   if(rtcpPacketTypeFlags & kRtcpFir)
   {
@@ -1931,9 +1932,9 @@
         return position;
       }
       TRACE_EVENT_INSTANT0("webrtc_rtp", "RTCPSender::FIR");
-      _fullIntraRequestCount++;
+      ++packet_type_counter_.fir_packets;
       TRACE_COUNTER_ID1("webrtc_rtp", "RTCP_FIRCount", _SSRC,
-                        _fullIntraRequestCount);
+                        packet_type_counter_.fir_packets);
   }
   if(rtcpPacketTypeFlags & kRtcpSli)
   {
@@ -2016,8 +2017,9 @@
       }
       TRACE_EVENT_INSTANT1("webrtc_rtp", "RTCPSender::NACK",
                            "nacks", TRACE_STR_COPY(nackString.c_str()));
-      _nackCount++;
-      TRACE_COUNTER_ID1("webrtc_rtp", "RTCP_NACKCount", _SSRC, _nackCount);
+      ++packet_type_counter_.nack_packets;
+      TRACE_COUNTER_ID1("webrtc_rtp", "RTCP_NACKCount", _SSRC,
+                        packet_type_counter_.nack_packets);
   }
   if(rtcpPacketTypeFlags & kRtcpXrVoipMetric)
   {
diff --git a/webrtc/modules/rtp_rtcp/source/rtcp_sender.h b/webrtc/modules/rtp_rtcp/source/rtcp_sender.h
index 9ed5824..cbbc32a 100644
--- a/webrtc/modules/rtp_rtcp/source/rtcp_sender.h
+++ b/webrtc/modules/rtp_rtcp/source/rtcp_sender.h
@@ -180,6 +180,8 @@
 
     void SetTargetBitrate(unsigned int target_bitrate);
 
+    void GetPacketTypeCounter(RtcpPacketTypeCounter* packet_counter) const;
+
 private:
     int32_t SendToNetwork(const uint8_t* dataBuffer, const uint16_t length);
 
@@ -342,10 +344,7 @@
     bool                _xrSendVoIPMetric;
     RTCPVoIPMetric      _xrVoIPMetric;
 
-    // Counters
-    uint32_t      _nackCount;
-    uint32_t      _pliCount;
-    uint32_t      _fullIntraRequestCount;
+    RtcpPacketTypeCounter packet_type_counter_;
 };
 }  // namespace webrtc
 
diff --git a/webrtc/modules/rtp_rtcp/source/rtp_rtcp_impl.cc b/webrtc/modules/rtp_rtcp/source/rtp_rtcp_impl.cc
index 9fdf3c8..b960941 100644
--- a/webrtc/modules/rtp_rtcp/source/rtp_rtcp_impl.cc
+++ b/webrtc/modules/rtp_rtcp/source/rtp_rtcp_impl.cc
@@ -983,6 +983,13 @@
   return rtcp_sender_.RemoveExternalReportBlock(ssrc);
 }
 
+void ModuleRtpRtcpImpl::GetRtcpPacketTypeCounters(
+    RtcpPacketTypeCounter* packets_sent,
+    RtcpPacketTypeCounter* packets_received) const {
+  rtcp_sender_.GetPacketTypeCounter(packets_sent);
+  rtcp_receiver_.GetPacketTypeCounter(packets_received);
+}
+
 // (REMB) Receiver Estimated Max Bitrate.
 bool ModuleRtpRtcpImpl::REMB() const {
   WEBRTC_TRACE(kTraceModuleCall, kTraceRtpRtcp, id_, "REMB()");
diff --git a/webrtc/modules/rtp_rtcp/source/rtp_rtcp_impl.h b/webrtc/modules/rtp_rtcp/source/rtp_rtcp_impl.h
index 8f25c2f..34c4fa2 100644
--- a/webrtc/modules/rtp_rtcp/source/rtp_rtcp_impl.h
+++ b/webrtc/modules/rtp_rtcp/source/rtp_rtcp_impl.h
@@ -197,10 +197,14 @@
 
   // Set received RTCP report block.
   virtual int32_t AddRTCPReportBlock(
-    const uint32_t ssrc, const RTCPReportBlock* receive_block) OVERRIDE;
+      const uint32_t ssrc, const RTCPReportBlock* receive_block) OVERRIDE;
 
   virtual int32_t RemoveRTCPReportBlock(const uint32_t ssrc) OVERRIDE;
 
+  virtual void GetRtcpPacketTypeCounters(
+      RtcpPacketTypeCounter* packets_sent,
+      RtcpPacketTypeCounter* packets_received) const OVERRIDE;
+
   // (REMB) Receiver Estimated Max Bitrate.
   virtual bool REMB() const OVERRIDE;
 
diff --git a/webrtc/modules/rtp_rtcp/source/rtp_rtcp_impl_unittest.cc b/webrtc/modules/rtp_rtcp/source/rtp_rtcp_impl_unittest.cc
index 0f28854..42c7c40 100644
--- a/webrtc/modules/rtp_rtcp/source/rtp_rtcp_impl_unittest.cc
+++ b/webrtc/modules/rtp_rtcp/source/rtp_rtcp_impl_unittest.cc
@@ -80,10 +80,22 @@
 
     transport_.SimulateNetworkDelay(kOneWayNetworkDelayMs, clock);
   }
+
+  RtcpPacketTypeCounter packets_sent_;
+  RtcpPacketTypeCounter packets_received_;
   scoped_ptr<ReceiveStatistics> receive_statistics_;
   SendTransport transport_;
   RtcpRttStatsTestImpl rtt_stats_;
   scoped_ptr<ModuleRtpRtcpImpl> impl_;
+
+  RtcpPacketTypeCounter RtcpSent() {
+    impl_->GetRtcpPacketTypeCounters(&packets_sent_, &packets_received_);
+    return packets_sent_;
+  }
+  RtcpPacketTypeCounter RtcpReceived() {
+    impl_->GetRtcpPacketTypeCounters(&packets_sent_, &packets_received_);
+    return packets_received_;
+  }
 };
 }  // namespace
 
@@ -172,4 +184,35 @@
   EXPECT_EQ(2 * kOneWayNetworkDelayMs, receiver_.rtt_stats_.LastProcessedRtt());
   EXPECT_EQ(2 * kOneWayNetworkDelayMs, receiver_.impl_->rtt_ms());
 }
+
+TEST_F(RtpRtcpImplTest, RtcpPacketTypeCounter_Nack) {
+  EXPECT_EQ(0U, sender_.RtcpReceived().nack_packets);
+  EXPECT_EQ(0U, receiver_.RtcpSent().nack_packets);
+  // Receive module sends a NACK.
+  const uint16_t kNackLength = 1;
+  uint16_t nack_list[kNackLength] = {123};
+  EXPECT_EQ(0, receiver_.impl_->SendNACK(nack_list, kNackLength));
+  EXPECT_EQ(1U, receiver_.RtcpSent().nack_packets);
+
+  // Send module receives the NACK.
+  EXPECT_EQ(1U, sender_.RtcpReceived().nack_packets);
+}
+
+TEST_F(RtpRtcpImplTest, RtcpPacketTypeCounter_FirAndPli) {
+  EXPECT_EQ(0U, sender_.RtcpReceived().fir_packets);
+  EXPECT_EQ(0U, receiver_.RtcpSent().fir_packets);
+  // Receive module sends a FIR.
+  EXPECT_EQ(0, receiver_.impl_->SendRTCP(kRtcpFir));
+  EXPECT_EQ(1U, receiver_.RtcpSent().fir_packets);
+  // Send module receives the FIR.
+  EXPECT_EQ(1U, sender_.RtcpReceived().fir_packets);
+
+  // Receive module sends a FIR and PLI.
+  EXPECT_EQ(0, receiver_.impl_->SendRTCP(kRtcpFir | kRtcpPli));
+  EXPECT_EQ(2U, receiver_.RtcpSent().fir_packets);
+  EXPECT_EQ(1U, receiver_.RtcpSent().pli_packets);
+  // Send module receives the FIR and PLI.
+  EXPECT_EQ(2U, sender_.RtcpReceived().fir_packets);
+  EXPECT_EQ(1U, sender_.RtcpReceived().pli_packets);
+}
 }  // namespace webrtc
diff --git a/webrtc/video_engine/include/vie_rtp_rtcp.h b/webrtc/video_engine/include/vie_rtp_rtcp.h
index 5ef1892..c76d2bb 100644
--- a/webrtc/video_engine/include/vie_rtp_rtcp.h
+++ b/webrtc/video_engine/include/vie_rtp_rtcp.h
@@ -360,6 +360,14 @@
   virtual int DeregisterReceiveChannelRtpStatisticsCallback(
       int video_channel, StreamDataCountersCallback* callback) = 0;
 
+
+  // Gets sent and received RTCP packet types.
+  // TODO(asapersson): Remove default implementation.
+  virtual int GetRtcpPacketTypeCounters(
+      int video_channel,
+      RtcpPacketTypeCounter* packets_sent,
+      RtcpPacketTypeCounter* packets_received) const { return -1; }
+
   // The function gets bandwidth usage statistics from the sent RTP streams in
   // bits/s.
   virtual int GetBandwidthUsage(const int video_channel,
diff --git a/webrtc/video_engine/vie_channel.cc b/webrtc/video_engine/vie_channel.cc
index 8d61cfc..695bce4 100644
--- a/webrtc/video_engine/vie_channel.cc
+++ b/webrtc/video_engine/vie_channel.cc
@@ -1381,6 +1381,22 @@
   vie_receiver_.GetReceiveStatistics()->RegisterRtpStatisticsCallback(callback);
 }
 
+void ViEChannel::GetRtcpPacketTypeCounters(
+    RtcpPacketTypeCounter* packets_sent,
+    RtcpPacketTypeCounter* packets_received) const {
+  rtp_rtcp_->GetRtcpPacketTypeCounters(packets_sent, packets_received);
+
+  CriticalSectionScoped cs(rtp_rtcp_cs_.get());
+  for (std::list<RtpRtcp*>::const_iterator it = simulcast_rtp_rtcp_.begin();
+       it != simulcast_rtp_rtcp_.end(); ++it) {
+    RtcpPacketTypeCounter sent;
+    RtcpPacketTypeCounter received;
+    (*it)->GetRtcpPacketTypeCounters(&sent, &received);
+    packets_sent->Add(sent);
+    packets_received->Add(received);
+  }
+}
+
 void ViEChannel::GetBandwidthUsage(uint32_t* total_bitrate_sent,
                                    uint32_t* video_bitrate_sent,
                                    uint32_t* fec_bitrate_sent,
diff --git a/webrtc/video_engine/vie_channel.h b/webrtc/video_engine/vie_channel.h
index 762f521..9991103 100644
--- a/webrtc/video_engine/vie_channel.h
+++ b/webrtc/video_engine/vie_channel.h
@@ -202,6 +202,9 @@
   void RegisterReceiveChannelRtpStatisticsCallback(
       StreamDataCountersCallback* callback);
 
+  void GetRtcpPacketTypeCounters(RtcpPacketTypeCounter* packets_sent,
+                                 RtcpPacketTypeCounter* packets_received) const;
+
   void GetBandwidthUsage(uint32_t* total_bitrate_sent,
                          uint32_t* video_bitrate_sent,
                          uint32_t* fec_bitrate_sent,
diff --git a/webrtc/video_engine/vie_rtp_rtcp_impl.cc b/webrtc/video_engine/vie_rtp_rtcp_impl.cc
index bd13df7..627c530 100644
--- a/webrtc/video_engine/vie_rtp_rtcp_impl.cc
+++ b/webrtc/video_engine/vie_rtp_rtcp_impl.cc
@@ -938,6 +938,23 @@
   return 0;
 }
 
+int ViERTP_RTCPImpl::GetRtcpPacketTypeCounters(
+    int video_channel,
+    RtcpPacketTypeCounter* packets_sent,
+    RtcpPacketTypeCounter* packets_received) const {
+  ViEChannelManagerScoped cs(*(shared_data_->channel_manager()));
+  ViEChannel* vie_channel = cs.Channel(video_channel);
+  if (!vie_channel) {
+    WEBRTC_TRACE(kTraceError, kTraceVideo,
+                 ViEId(shared_data_->instance_id(), video_channel),
+                 "%s: Channel %d doesn't exist", __FUNCTION__, video_channel);
+    shared_data_->SetLastError(kViERtpRtcpInvalidChannelId);
+    return -1;
+  }
+  vie_channel->GetRtcpPacketTypeCounters(packets_sent, packets_received);
+  return 0;
+}
+
 int ViERTP_RTCPImpl::GetBandwidthUsage(const int video_channel,
                                        unsigned int& total_bitrate_sent,
                                        unsigned int& video_bitrate_sent,
diff --git a/webrtc/video_engine/vie_rtp_rtcp_impl.h b/webrtc/video_engine/vie_rtp_rtcp_impl.h
index 74e69ce..0341d74 100644
--- a/webrtc/video_engine/vie_rtp_rtcp_impl.h
+++ b/webrtc/video_engine/vie_rtp_rtcp_impl.h
@@ -99,6 +99,10 @@
   virtual int GetRtpStatistics(const int video_channel,
                                StreamDataCounters& sent,
                                StreamDataCounters& received) const;
+  virtual int GetRtcpPacketTypeCounters(
+      int video_channel,
+      RtcpPacketTypeCounter* packets_sent,
+      RtcpPacketTypeCounter* packets_received) const;
   virtual int GetBandwidthUsage(const int video_channel,
                                 unsigned int& total_bitrate_sent,
                                 unsigned int& video_bitrate_sent,