NetEq: Simplify the dependencies of GetNetworkStatistics

Adds a new method PopulateDelayManagerStats which takes care of the
fields that needed information from the DelayManager.

Also adds a new test for StatisticsCalculator made practically
feasible by the refactoring.

Bug: webrtc:7554
Change-Id: Iff5cb5e209c276bd2784f2ccf73be8f619b1d955
Reviewed-on: https://webrtc-review.googlesource.com/3181
Reviewed-by: Gustaf Ullberg <gustaf@webrtc.org>
Commit-Queue: Henrik Lundin <henrik.lundin@webrtc.org>
Cr-Commit-Position: refs/heads/master@{#19957}
diff --git a/modules/audio_coding/neteq/neteq_impl.cc b/modules/audio_coding/neteq/neteq_impl.cc
index cdf590b..2d50225 100644
--- a/modules/audio_coding/neteq/neteq_impl.cc
+++ b/modules/audio_coding/neteq/neteq_impl.cc
@@ -374,9 +374,11 @@
       sync_buffer_->FutureLength();
   assert(delay_manager_.get());
   assert(decision_logic_.get());
+  const int ms_per_packet = rtc::dchecked_cast<int>(
+      decision_logic_->packet_length_samples() / (fs_hz_ / 1000));
+  stats_.PopulateDelayManagerStats(ms_per_packet, *delay_manager_.get(), stats);
   stats_.GetNetworkStatistics(fs_hz_, total_samples_in_buffers,
-                              decoder_frame_length_, *delay_manager_.get(),
-                              *decision_logic_.get(), stats);
+                              decoder_frame_length_, stats);
   return 0;
 }
 
diff --git a/modules/audio_coding/neteq/statistics_calculator.cc b/modules/audio_coding/neteq/statistics_calculator.cc
index 09ced6a..4e034e6 100644
--- a/modules/audio_coding/neteq/statistics_calculator.cc
+++ b/modules/audio_coding/neteq/statistics_calculator.cc
@@ -14,7 +14,6 @@
 #include <string.h>  // memset
 #include <algorithm>
 
-#include "modules/audio_coding/neteq/decision_logic.h"
 #include "modules/audio_coding/neteq/delay_manager.h"
 #include "rtc_base/checks.h"
 #include "rtc_base/safe_conversions.h"
@@ -255,24 +254,13 @@
     int fs_hz,
     size_t num_samples_in_buffers,
     size_t samples_per_packet,
-    const DelayManager& delay_manager,
-    const DecisionLogic& decision_logic,
     NetEqNetworkStatistics *stats) {
-  if (fs_hz <= 0 || !stats) {
-    assert(false);
-    return;
-  }
+  RTC_DCHECK_GT(fs_hz, 0);
+  RTC_DCHECK(stats);
 
   stats->added_zero_samples = added_zero_samples_;
   stats->current_buffer_size_ms =
       static_cast<uint16_t>(num_samples_in_buffers * 1000 / fs_hz);
-  const int ms_per_packet = rtc::dchecked_cast<int>(
-      decision_logic.packet_length_samples() / (fs_hz / 1000));
-  stats->preferred_buffer_size_ms = (delay_manager.TargetLevel() >> 8) *
-      ms_per_packet;
-  stats->jitter_peaks_found = delay_manager.PeakFound();
-  stats->clockdrift_ppm =
-      rtc::saturated_cast<int32_t>(delay_manager.EstimatedClockDriftPpm());
 
   stats->packet_loss_rate =
       CalculateQ14Ratio(lost_timestamps_, timestamps_since_last_report_);
@@ -331,6 +319,18 @@
   Reset();
 }
 
+void StatisticsCalculator::PopulateDelayManagerStats(
+    int ms_per_packet,
+    const DelayManager& delay_manager,
+    NetEqNetworkStatistics* stats) {
+  RTC_DCHECK(stats);
+  stats->preferred_buffer_size_ms =
+      (delay_manager.TargetLevel() >> 8) * ms_per_packet;
+  stats->jitter_peaks_found = delay_manager.PeakFound();
+  stats->clockdrift_ppm =
+      rtc::saturated_cast<int32_t>(delay_manager.EstimatedClockDriftPpm());
+}
+
 NetEqLifetimeStatistics StatisticsCalculator::GetLifetimeStatistics() const {
   return lifetime_stats_;
 }
diff --git a/modules/audio_coding/neteq/statistics_calculator.h b/modules/audio_coding/neteq/statistics_calculator.h
index 232ca9a..5c2fbf3 100644
--- a/modules/audio_coding/neteq/statistics_calculator.h
+++ b/modules/audio_coding/neteq/statistics_calculator.h
@@ -20,8 +20,6 @@
 
 namespace webrtc {
 
-// Forward declarations.
-class DecisionLogic;
 class DelayManager;
 
 // This class handles various network statistics in NetEq.
@@ -91,14 +89,22 @@
   // Returns the current network statistics in |stats|. The current sample rate
   // is |fs_hz|, the total number of samples in packet buffer and sync buffer
   // yet to play out is |num_samples_in_buffers|, and the number of samples per
-  // packet is |samples_per_packet|.
+  // packet is |samples_per_packet|. The method does not populate
+  // |preferred_buffer_size_ms|, |jitter_peaks_found| or |clockdrift_ppm|; use
+  // the PopulateDelayManagerStats method for those.
   void GetNetworkStatistics(int fs_hz,
                             size_t num_samples_in_buffers,
                             size_t samples_per_packet,
-                            const DelayManager& delay_manager,
-                            const DecisionLogic& decision_logic,
                             NetEqNetworkStatistics *stats);
 
+  // Populates |preferred_buffer_size_ms|, |jitter_peaks_found| and
+  // |clockdrift_ppm| in |stats|. This is a convenience method, and does not
+  // strictly have to be in the StatisticsCalculator class, but it makes sense
+  // since all other stats fields are populated by that class.
+  static void PopulateDelayManagerStats(int ms_per_packet,
+                                        const DelayManager& delay_manager,
+                                        NetEqNetworkStatistics* stats);
+
   // Returns a copy of this class's lifetime statistics. These statistics are
   // never reset.
   NetEqLifetimeStatistics GetLifetimeStatistics() const;
diff --git a/modules/audio_coding/neteq/statistics_calculator_unittest.cc b/modules/audio_coding/neteq/statistics_calculator_unittest.cc
index 0cc868a..0a4901d 100644
--- a/modules/audio_coding/neteq/statistics_calculator_unittest.cc
+++ b/modules/audio_coding/neteq/statistics_calculator_unittest.cc
@@ -63,4 +63,45 @@
   EXPECT_EQ(200u, stats.GetLifetimeStatistics().concealed_samples);
 }
 
+TEST(StatisticsCalculator, ExpandedSamplesCorrection) {
+  StatisticsCalculator stats;
+  NetEqNetworkStatistics stats_output;
+  constexpr int kSampleRateHz = 48000;
+  constexpr int k10MsSamples = kSampleRateHz / 100;
+  constexpr int kPacketSizeMs = 20;
+  constexpr size_t kSamplesPerPacket = kPacketSizeMs * kSampleRateHz / 1000;
+  // Assume 2 packets in the buffer.
+  constexpr size_t kNumSamplesInBuffer = 2 * kSamplesPerPacket;
+
+  // Advance time by 10 ms.
+  stats.IncreaseCounter(k10MsSamples, kSampleRateHz);
+
+  stats.GetNetworkStatistics(kSampleRateHz, kNumSamplesInBuffer,
+                             kSamplesPerPacket, &stats_output);
+
+  EXPECT_EQ(0u, stats_output.expand_rate);
+  EXPECT_EQ(0u, stats_output.speech_expand_rate);
+
+  // Correct with a negative value.
+  stats.ExpandedVoiceSamplesCorrection(-100);
+  stats.ExpandedNoiseSamplesCorrection(-100);
+  stats.IncreaseCounter(k10MsSamples, kSampleRateHz);
+  stats.GetNetworkStatistics(kSampleRateHz, kNumSamplesInBuffer,
+                             kSamplesPerPacket, &stats_output);
+  // Expect no change, since negative values are disallowed.
+  EXPECT_EQ(0u, stats_output.expand_rate);
+  EXPECT_EQ(0u, stats_output.speech_expand_rate);
+
+  // Correct with a positive value.
+  stats.ExpandedVoiceSamplesCorrection(50);
+  stats.ExpandedNoiseSamplesCorrection(200);
+  stats.IncreaseCounter(k10MsSamples, kSampleRateHz);
+  stats.GetNetworkStatistics(kSampleRateHz, kNumSamplesInBuffer,
+                             kSamplesPerPacket, &stats_output);
+  // Calculate expected rates in Q14. Expand rate is noise + voice, while
+  // speech expand rate is only voice.
+  EXPECT_EQ(((50u + 200u) << 14) / k10MsSamples, stats_output.expand_rate);
+  EXPECT_EQ((50u << 14) / k10MsSamples, stats_output.speech_expand_rate);
+}
+
 }  // namespace webrtc