Adding NetEq performance test to webrtc_perf_tests

The performance test is based on the neteq4_speed_test application. The
bulk of the test code is extracted into a test class, and included into
the neteq_unittest_tools target. The actual gtest that runs the
performance test is implemented in neteq_performance_unittest.cc, and
built as a part of webrtc_perf_tests.

The old stand-alone test application is now made dependent on the new
test class, to avoid code duplication.

BUG=2397
R=andrew@webrtc.org, kjellander@webrtc.org, turaj@webrtc.org

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

git-svn-id: http://webrtc.googlecode.com/svn/trunk@5362 4adac7df-926f-26a2-2b94-8c16560cd09d
diff --git a/webrtc/modules/audio_coding/neteq/neteq.gypi b/webrtc/modules/audio_coding/neteq/neteq.gypi
index 27e5c37..a8acfb3 100644
--- a/webrtc/modules/audio_coding/neteq/neteq.gypi
+++ b/webrtc/modules/audio_coding/neteq/neteq.gypi
@@ -167,6 +167,7 @@
             'PCM16B',
             'neteq_unittest_tools',
             '<(DEPTH)/third_party/gflags/gflags.gyp:gflags',
+            '<(webrtc_root)/test/test.gyp:test_support_main',
           ],
           'sources': [
             'test/neteq_speed_test.cc',
diff --git a/webrtc/modules/audio_coding/neteq4/neteq.gypi b/webrtc/modules/audio_coding/neteq4/neteq.gypi
index 41fdb31..4660109 100644
--- a/webrtc/modules/audio_coding/neteq4/neteq.gypi
+++ b/webrtc/modules/audio_coding/neteq4/neteq.gypi
@@ -162,7 +162,7 @@
           'dependencies': [
             '<(DEPTH)/testing/gmock.gyp:gmock',
             '<(DEPTH)/testing/gtest.gyp:gtest',
-            '<(webrtc_root)/test/test.gyp:test_support_main',
+            'PCM16B',  # Needed by neteq_performance_test.
           ],
           'direct_dependent_settings': {
             'include_dirs': [
@@ -177,6 +177,8 @@
             'tools/audio_loop.h',
             'tools/input_audio_file.cc',
             'tools/input_audio_file.h',
+            'tools/neteq_performance_test.cc',
+            'tools/neteq_performance_test.h',
             'tools/rtp_generator.cc',
             'tools/rtp_generator.h',
           ],
diff --git a/webrtc/modules/audio_coding/neteq4/neteq_tests.gypi b/webrtc/modules/audio_coding/neteq4/neteq_tests.gypi
index a2b9265..c74466d 100644
--- a/webrtc/modules/audio_coding/neteq4/neteq_tests.gypi
+++ b/webrtc/modules/audio_coding/neteq4/neteq_tests.gypi
@@ -146,6 +146,7 @@
         'neteq_unittest_tools',
         'PCM16B',
         '<(DEPTH)/third_party/gflags/gflags.gyp:gflags',
+        '<(webrtc_root)/test/test.gyp:test_support_main',
       ],
       'sources': [
         'test/neteq_speed_test.cc',
diff --git a/webrtc/modules/audio_coding/neteq4/test/neteq_performance_unittest.cc b/webrtc/modules/audio_coding/neteq4/test/neteq_performance_unittest.cc
new file mode 100644
index 0000000..aa33649
--- /dev/null
+++ b/webrtc/modules/audio_coding/neteq4/test/neteq_performance_unittest.cc
@@ -0,0 +1,25 @@
+/*
+ *  Copyright (c) 2014 The WebRTC project authors. All Rights Reserved.
+ *
+ *  Use of this source code is governed by a BSD-style license
+ *  that can be found in the LICENSE file in the root of the source
+ *  tree. An additional intellectual property rights grant can be found
+ *  in the file PATENTS.  All contributing project authors may
+ *  be found in the AUTHORS file in the root of the source tree.
+ */
+
+#include "testing/gtest/include/gtest/gtest.h"
+#include "webrtc/modules/audio_coding/neteq4/tools/neteq_performance_test.h"
+#include "webrtc/test/testsupport/perf_test.h"
+#include "webrtc/typedefs.h"
+
+TEST(NetEqPerformanceTest, Run) {
+  const int kSimulationTimeMs = 1000000;
+  const int kLossPeriod = 10;  // Drop every 10th packet.
+  const double kDriftFactor = 0.1;
+  int64_t runtime = webrtc::test::NetEqPerformanceTest::Run(
+      kSimulationTimeMs, kLossPeriod, kDriftFactor);
+  ASSERT_GT(runtime, 0);
+  webrtc::test::PrintResult(
+      "neteq4-runtime", "", "", runtime, "ms", true);
+}
diff --git a/webrtc/modules/audio_coding/neteq4/test/neteq_speed_test.cc b/webrtc/modules/audio_coding/neteq4/test/neteq_speed_test.cc
index 34f0de4..cecd48b 100644
--- a/webrtc/modules/audio_coding/neteq4/test/neteq_speed_test.cc
+++ b/webrtc/modules/audio_coding/neteq4/test/neteq_speed_test.cc
@@ -13,18 +13,9 @@
 #include <iostream>
 
 #include "gflags/gflags.h"
-#include "webrtc/modules/audio_coding/codecs/pcm16b/include/pcm16b.h"
-#include "webrtc/modules/audio_coding/neteq4/interface/neteq.h"
-#include "webrtc/modules/audio_coding/neteq4/tools/audio_loop.h"
-#include "webrtc/modules/audio_coding/neteq4/tools/rtp_generator.h"
-#include "webrtc/test/testsupport/fileutils.h"
+#include "webrtc/modules/audio_coding/neteq4/tools/neteq_performance_test.h"
 #include "webrtc/typedefs.h"
 
-using webrtc::NetEq;
-using webrtc::test::AudioLoop;
-using webrtc::test::RtpGenerator;
-using webrtc::WebRtcRTPHeader;
-
 // Flag validators.
 static bool ValidateRuntime(const char* flagname, int value) {
   if (value > 0)  // Value is ok.
@@ -59,15 +50,6 @@
     google::RegisterFlagValidator(&FLAGS_drift, &ValidateDriftfactor);
 
 int main(int argc, char* argv[]) {
-  static const int kMaxChannels = 1;
-  static const int kMaxSamplesPerMs = 48000 / 1000;
-  static const int kOutputBlockSizeMs = 10;
-  const std::string kInputFileName =
-        webrtc::test::ResourcePath("audio_coding/testfile32kHz", "pcm");
-  const int kSampRateHz = 32000;
-  const webrtc::NetEqDecoder kDecoderType = webrtc::kDecoderPCM16Bswb32kHz;
-  const int kPayloadType = 95;
-
   std::string program_name = argv[0];
   std::string usage = "Tool for measuring the speed of NetEq.\n"
       "Usage: " + program_name + " [options]\n\n"
@@ -84,101 +66,15 @@
     return 0;
   }
 
-  // Initialize NetEq instance.
-  NetEq* neteq = NetEq::Create(kSampRateHz);
-  // Register decoder in |neteq|.
-  int error;
-  error = neteq->RegisterPayloadType(kDecoderType, kPayloadType);
-  if (error) {
-    std::cerr << "Cannot register decoder." << std::endl;
-    exit(1);
-  }
-
-  // Set up AudioLoop object.
-  AudioLoop audio_loop;
-  const size_t kMaxLoopLengthSamples = kSampRateHz * 10;  // 10 second loop.
-  const size_t kInputBlockSizeSamples = 60 * kSampRateHz / 1000;  // 60 ms.
-  if (!audio_loop.Init(kInputFileName, kMaxLoopLengthSamples,
-                       kInputBlockSizeSamples)) {
-    std::cerr << "Cannot initialize AudioLoop object." << std::endl;
-    exit(1);
-  }
-
-  int32_t time_now_ms = 0;
-
-  // Get first input packet.
-  WebRtcRTPHeader rtp_header;
-  RtpGenerator rtp_gen(kSampRateHz / 1000);
-  // Start with positive drift first half of simulation.
-  double drift_factor = 0.1;
-  rtp_gen.set_drift_factor(drift_factor);
-  bool drift_flipped = false;
-  int32_t packet_input_time_ms =
-      rtp_gen.GetRtpHeader(kPayloadType, kInputBlockSizeSamples, &rtp_header);
-  const int16_t* input_samples = audio_loop.GetNextBlock();
-  if (!input_samples) exit(1);
-  uint8_t input_payload[kInputBlockSizeSamples * sizeof(int16_t)];
-  int payload_len = WebRtcPcm16b_Encode(const_cast<int16_t*>(input_samples),
-                                        kInputBlockSizeSamples,
-                                        input_payload);
-  assert(payload_len == kInputBlockSizeSamples * sizeof(int16_t));
-
-  // Main loop.
-  while (time_now_ms < FLAGS_runtime_ms) {
-    while (packet_input_time_ms <= time_now_ms) {
-      // Drop every N packets, where N = FLAGS_lossrate.
-      bool lost = false;
-      if (FLAGS_lossrate > 0) {
-        lost = ((rtp_header.header.sequenceNumber - 1) % FLAGS_lossrate) == 0;
-      }
-      if (!lost) {
-        // Insert packet.
-        int error = neteq->InsertPacket(
-            rtp_header, input_payload, payload_len,
-            packet_input_time_ms * kSampRateHz / 1000);
-        if (error != NetEq::kOK) {
-          std::cerr << "InsertPacket returned error code " <<
-              neteq->LastError() << std::endl;
-          exit(1);
-        }
-      }
-
-      // Get next packet.
-      packet_input_time_ms = rtp_gen.GetRtpHeader(kPayloadType,
-                                                  kInputBlockSizeSamples,
-                                                  &rtp_header);
-      input_samples = audio_loop.GetNextBlock();
-      if (!input_samples) exit(1);
-      payload_len = WebRtcPcm16b_Encode(const_cast<int16_t*>(input_samples),
-                                        kInputBlockSizeSamples,
-                                        input_payload);
-      assert(payload_len == kInputBlockSizeSamples * sizeof(int16_t));
-    }
-
-    // Get output audio, but don't do anything with it.
-    static const int kOutDataLen = kOutputBlockSizeMs * kMaxSamplesPerMs *
-        kMaxChannels;
-    int16_t out_data[kOutDataLen];
-    int num_channels;
-    int samples_per_channel;
-    int error = neteq->GetAudio(kOutDataLen, out_data, &samples_per_channel,
-                                &num_channels, NULL);
-    if (error != NetEq::kOK) {
-      std::cerr << "GetAudio returned error code " <<
-          neteq->LastError() << std::endl;
-      exit(1);
-    }
-    assert(samples_per_channel == kSampRateHz * 10 / 1000);
-
-    time_now_ms += kOutputBlockSizeMs;
-    if (time_now_ms >= FLAGS_runtime_ms / 2 && !drift_flipped) {
-      // Apply negative drift second half of simulation.
-      rtp_gen.set_drift_factor(-drift_factor);
-      drift_flipped = true;
-    }
+  int64_t result =
+      webrtc::test::NetEqPerformanceTest::Run(FLAGS_runtime_ms, FLAGS_lossrate,
+                                              FLAGS_drift);
+  if (result <= 0) {
+    std::cout << "There was an error" << std::endl;
+    return -1;
   }
 
   std::cout << "Simulation done" << std::endl;
-  delete neteq;
+  std::cout << "Runtime = " << result << " ms" << std::endl;
   return 0;
 }
diff --git a/webrtc/modules/audio_coding/neteq4/tools/neteq_performance_test.cc b/webrtc/modules/audio_coding/neteq4/tools/neteq_performance_test.cc
new file mode 100644
index 0000000..203ea04
--- /dev/null
+++ b/webrtc/modules/audio_coding/neteq4/tools/neteq_performance_test.cc
@@ -0,0 +1,130 @@
+/*
+ *  Copyright (c) 2014 The WebRTC project authors. All Rights Reserved.
+ *
+ *  Use of this source code is governed by a BSD-style license
+ *  that can be found in the LICENSE file in the root of the source
+ *  tree. An additional intellectual property rights grant can be found
+ *  in the file PATENTS.  All contributing project authors may
+ *  be found in the AUTHORS file in the root of the source tree.
+ */
+
+#include "webrtc/modules/audio_coding/neteq4/tools/neteq_performance_test.h"
+
+#include "webrtc/modules/audio_coding/codecs/pcm16b/include/pcm16b.h"
+#include "webrtc/modules/audio_coding/neteq4/interface/neteq.h"
+#include "webrtc/modules/audio_coding/neteq4/tools/audio_loop.h"
+#include "webrtc/modules/audio_coding/neteq4/tools/rtp_generator.h"
+#include "webrtc/system_wrappers/interface/clock.h"
+#include "webrtc/test/testsupport/fileutils.h"
+#include "webrtc/typedefs.h"
+
+using webrtc::NetEq;
+using webrtc::test::AudioLoop;
+using webrtc::test::RtpGenerator;
+using webrtc::WebRtcRTPHeader;
+
+namespace webrtc {
+namespace test {
+
+int64_t NetEqPerformanceTest::Run(int runtime_ms,
+                                  int lossrate,
+                                  double drift_factor) {
+  const std::string kInputFileName =
+      webrtc::test::ResourcePath("audio_coding/testfile32kHz", "pcm");
+  const int kSampRateHz = 32000;
+  const webrtc::NetEqDecoder kDecoderType = webrtc::kDecoderPCM16Bswb32kHz;
+  const int kPayloadType = 95;
+
+  // Initialize NetEq instance.
+  NetEq* neteq = NetEq::Create(kSampRateHz);
+  // Register decoder in |neteq|.
+  if (neteq->RegisterPayloadType(kDecoderType, kPayloadType) != 0)
+    return -1;
+
+  // Set up AudioLoop object.
+  AudioLoop audio_loop;
+  const size_t kMaxLoopLengthSamples = kSampRateHz * 10;  // 10 second loop.
+  const size_t kInputBlockSizeSamples = 60 * kSampRateHz / 1000;  // 60 ms.
+  if (!audio_loop.Init(kInputFileName, kMaxLoopLengthSamples,
+                       kInputBlockSizeSamples))
+    return -1;
+
+  int32_t time_now_ms = 0;
+
+  // Get first input packet.
+  WebRtcRTPHeader rtp_header;
+  RtpGenerator rtp_gen(kSampRateHz / 1000);
+  // Start with positive drift first half of simulation.
+  rtp_gen.set_drift_factor(drift_factor);
+  bool drift_flipped = false;
+  int32_t packet_input_time_ms =
+      rtp_gen.GetRtpHeader(kPayloadType, kInputBlockSizeSamples, &rtp_header);
+  const int16_t* input_samples = audio_loop.GetNextBlock();
+  if (!input_samples) exit(1);
+  uint8_t input_payload[kInputBlockSizeSamples * sizeof(int16_t)];
+  int payload_len = WebRtcPcm16b_Encode(const_cast<int16_t*>(input_samples),
+                                        kInputBlockSizeSamples,
+                                        input_payload);
+  assert(payload_len == kInputBlockSizeSamples * sizeof(int16_t));
+
+  // Main loop.
+  webrtc::Clock* clock = webrtc::Clock::GetRealTimeClock();
+  int64_t start_time_ms = clock->TimeInMilliseconds();
+  while (time_now_ms < runtime_ms) {
+    while (packet_input_time_ms <= time_now_ms) {
+      // Drop every N packets, where N = FLAGS_lossrate.
+      bool lost = false;
+      if (lossrate > 0) {
+        lost = ((rtp_header.header.sequenceNumber - 1) % lossrate) == 0;
+      }
+      if (!lost) {
+        // Insert packet.
+        int error = neteq->InsertPacket(
+            rtp_header, input_payload, payload_len,
+            packet_input_time_ms * kSampRateHz / 1000);
+        if (error != NetEq::kOK)
+          return -1;
+      }
+
+      // Get next packet.
+      packet_input_time_ms = rtp_gen.GetRtpHeader(kPayloadType,
+                                                  kInputBlockSizeSamples,
+                                                  &rtp_header);
+      input_samples = audio_loop.GetNextBlock();
+      if (!input_samples) return -1;
+      payload_len = WebRtcPcm16b_Encode(const_cast<int16_t*>(input_samples),
+                                        kInputBlockSizeSamples,
+                                        input_payload);
+      assert(payload_len == kInputBlockSizeSamples * sizeof(int16_t));
+    }
+
+    // Get output audio, but don't do anything with it.
+    static const int kMaxChannels = 1;
+    static const int kMaxSamplesPerMs = 48000 / 1000;
+    static const int kOutputBlockSizeMs = 10;
+    static const int kOutDataLen = kOutputBlockSizeMs * kMaxSamplesPerMs *
+        kMaxChannels;
+    int16_t out_data[kOutDataLen];
+    int num_channels;
+    int samples_per_channel;
+    int error = neteq->GetAudio(kOutDataLen, out_data, &samples_per_channel,
+                                &num_channels, NULL);
+    if (error != NetEq::kOK)
+      return -1;
+
+    assert(samples_per_channel == kSampRateHz * 10 / 1000);
+
+    time_now_ms += kOutputBlockSizeMs;
+    if (time_now_ms >= runtime_ms / 2 && !drift_flipped) {
+      // Apply negative drift second half of simulation.
+      rtp_gen.set_drift_factor(-drift_factor);
+      drift_flipped = true;
+    }
+  }
+  int64_t end_time_ms = clock->TimeInMilliseconds();
+  delete neteq;
+  return end_time_ms - start_time_ms;
+}
+
+}  // namespace test
+}  // namespace webrtc
diff --git a/webrtc/modules/audio_coding/neteq4/tools/neteq_performance_test.h b/webrtc/modules/audio_coding/neteq4/tools/neteq_performance_test.h
new file mode 100644
index 0000000..1b205c0
--- /dev/null
+++ b/webrtc/modules/audio_coding/neteq4/tools/neteq_performance_test.h
@@ -0,0 +1,32 @@
+/*
+ *  Copyright (c) 2014 The WebRTC project authors. All Rights Reserved.
+ *
+ *  Use of this source code is governed by a BSD-style license
+ *  that can be found in the LICENSE file in the root of the source
+ *  tree. An additional intellectual property rights grant can be found
+ *  in the file PATENTS.  All contributing project authors may
+ *  be found in the AUTHORS file in the root of the source tree.
+ */
+
+#ifndef WEBRTC_MODULES_AUDIO_CODING_NETEQ4_TOOLS_NETEQ_PERFORMANCE_TEST_H_
+#define WEBRTC_MODULES_AUDIO_CODING_NETEQ4_TOOLS_NETEQ_PERFORMANCE_TEST_H_
+
+#include "webrtc/typedefs.h"
+
+namespace webrtc {
+namespace test {
+
+class NetEqPerformanceTest {
+ public:
+  // Runs a performance test with parameters as follows:
+  //   |runtime_ms|: the simulation time, i.e., the duration of the audio data.
+  //   |lossrate|: drop one out of |lossrate| packets, e.g., one out of 10.
+  //   |drift_factor|: clock drift in [0, 1].
+  // Returns the runtime in ms.
+  static int64_t Run(int runtime_ms, int lossrate, double drift_factor);
+};
+
+}  // namespace test
+}  // namespace webrtc
+
+#endif  // WEBRTC_MODULES_AUDIO_CODING_NETEQ4_TOOLS_NETEQ_PERFORMANCE_TEST_H_
diff --git a/webrtc/webrtc_tests.gypi b/webrtc/webrtc_tests.gypi
index b60660a..57fd907 100644
--- a/webrtc/webrtc_tests.gypi
+++ b/webrtc/webrtc_tests.gypi
@@ -54,6 +54,7 @@
       'target_name': 'webrtc_perf_tests',
       'type': '<(gtest_target_type)',
       'sources': [
+        'modules/audio_coding/neteq4/test/neteq_performance_unittest.cc',
         'test/test_main.cc',
         'video/call_perf_tests.cc',
         'video/full_stack.cc',
@@ -62,6 +63,7 @@
       'dependencies': [
         '<(DEPTH)/testing/gtest.gyp:gtest',
         '<(DEPTH)/third_party/gflags/gflags.gyp:gflags',
+        'modules/modules.gyp:neteq_unittest_tools',  # Needed by neteq_performance_unittest.
         'modules/modules.gyp:rtp_rtcp',
         'test/webrtc_test_common.gyp:webrtc_test_common',
         'webrtc',