AEC-m and AEC-2 fuzzing.

Going through the coverage of audio_processing_fuzzer, it was noticed
that it didn't cover AEC-m and AEC-2 code. Therefore this CL adds 2
fuzzer targets that only fuzz the previous generation echo cancellers.

To avoid code duplication, the APM running code was broken out in a
new GN target. We have also changed all fuzzing code to use the
FuzzDataHelper class to avoid manual pointer arithmetic.

Bug: webrtc:7820
Change-Id: Ifea3266e396b487952a736945577fccea15d0e01
Reviewed-on: https://webrtc-review.googlesource.com/36500
Reviewed-by: Henrik Lundin <henrik.lundin@webrtc.org>
Reviewed-by: Sam Zackrisson <saza@webrtc.org>
Commit-Queue: Alex Loiko <aleloi@webrtc.org>
Cr-Commit-Position: refs/heads/master@{#21638}
diff --git a/test/fuzzers/BUILD.gn b/test/fuzzers/BUILD.gn
index 1a400c8..43df618 100644
--- a/test/fuzzers/BUILD.gn
+++ b/test/fuzzers/BUILD.gn
@@ -421,14 +421,13 @@
     "../../voice_engine",
   ]
 }
-
-webrtc_fuzzer_test("audio_processing_fuzzer") {
+rtc_static_library("audio_processing_fuzzer_helper") {
   sources = [
-    "audio_processing_fuzzer.cc",
-    "audio_processing_fuzzer.h",
-    "audio_processing_fuzzer_configs.cc",
+    "audio_processing_fuzzer_helper.cc",
+    "audio_processing_fuzzer_helper.h",
   ]
   deps = [
+    ":fuzz_data_helper",
     "../../api:optional",
     "../../modules:module_api",
     "../../modules/audio_processing",
@@ -437,6 +436,17 @@
   ]
 }
 
+webrtc_fuzzer_test("audio_processing_fuzzer") {
+  sources = [
+    "audio_processing_configs_fuzzer.cc",
+  ]
+  deps = [
+    ":audio_processing_fuzzer_helper",
+    ":fuzz_data_helper",
+    "../../modules/audio_processing",
+  ]
+}
+
 webrtc_fuzzer_test("comfort_noise_decoder_fuzzer") {
   sources = [
     "comfort_noise_decoder_fuzzer.cc",
diff --git a/test/fuzzers/audio_processing_configs_fuzzer.cc b/test/fuzzers/audio_processing_configs_fuzzer.cc
new file mode 100644
index 0000000..81baab1
--- /dev/null
+++ b/test/fuzzers/audio_processing_configs_fuzzer.cc
@@ -0,0 +1,96 @@
+/*
+ *  Copyright (c) 2017 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 "modules/audio_processing/include/audio_processing.h"
+#include "test/fuzzers/audio_processing_fuzzer_helper.h"
+#include "test/fuzzers/fuzz_data_helper.h"
+
+namespace webrtc {
+namespace {
+std::unique_ptr<AudioProcessing> CreateApm(test::FuzzDataHelper* fuzz_data) {
+  // Parse boolean values for optionally enabling different
+  // configurable public components of APM.
+  bool exp_agc = fuzz_data->ReadOrDefaultValue(true);
+  bool exp_ns = fuzz_data->ReadOrDefaultValue(true);
+  bool bf = fuzz_data->ReadOrDefaultValue(true);
+  bool ef = fuzz_data->ReadOrDefaultValue(true);
+  bool raf = fuzz_data->ReadOrDefaultValue(true);
+  bool da = fuzz_data->ReadOrDefaultValue(true);
+  bool ie = fuzz_data->ReadOrDefaultValue(true);
+  bool red = fuzz_data->ReadOrDefaultValue(true);
+  bool lc = fuzz_data->ReadOrDefaultValue(true);
+  bool hpf = fuzz_data->ReadOrDefaultValue(true);
+  bool aec3 = fuzz_data->ReadOrDefaultValue(true);
+
+  bool use_aec = fuzz_data->ReadOrDefaultValue(true);
+  bool use_aecm = fuzz_data->ReadOrDefaultValue(true);
+  bool use_agc = fuzz_data->ReadOrDefaultValue(true);
+  bool use_ns = fuzz_data->ReadOrDefaultValue(true);
+  bool use_le = fuzz_data->ReadOrDefaultValue(true);
+  bool use_vad = fuzz_data->ReadOrDefaultValue(true);
+  bool use_agc_limiter = fuzz_data->ReadOrDefaultValue(true);
+
+  // Filter out incompatible settings that lead to CHECK failures.
+  if (use_aecm && use_aec) {
+    return nullptr;
+  }
+
+  // Components can be enabled through webrtc::Config and
+  // webrtc::AudioProcessingConfig.
+  Config config;
+
+  std::unique_ptr<EchoControlFactory> echo_control_factory;
+  if (aec3) {
+    echo_control_factory.reset(new EchoCanceller3Factory());
+  }
+
+  config.Set<ExperimentalAgc>(new ExperimentalAgc(exp_agc));
+  config.Set<ExperimentalNs>(new ExperimentalNs(exp_ns));
+  if (bf) {
+    config.Set<Beamforming>(new Beamforming());
+  }
+  config.Set<ExtendedFilter>(new ExtendedFilter(ef));
+  config.Set<RefinedAdaptiveFilter>(new RefinedAdaptiveFilter(raf));
+  config.Set<DelayAgnostic>(new DelayAgnostic(da));
+  config.Set<Intelligibility>(new Intelligibility(ie));
+
+  std::unique_ptr<AudioProcessing> apm(
+      AudioProcessingBuilder()
+          .SetEchoControlFactory(std::move(echo_control_factory))
+          .Create(config));
+
+  webrtc::AudioProcessing::Config apm_config;
+  apm_config.residual_echo_detector.enabled = red;
+  apm_config.level_controller.enabled = lc;
+  apm_config.high_pass_filter.enabled = hpf;
+
+  apm->ApplyConfig(apm_config);
+
+  apm->echo_cancellation()->Enable(use_aec);
+  apm->echo_control_mobile()->Enable(use_aecm);
+  apm->gain_control()->Enable(use_agc);
+  apm->noise_suppression()->Enable(use_ns);
+  apm->level_estimator()->Enable(use_le);
+  apm->voice_detection()->Enable(use_vad);
+  apm->gain_control()->enable_limiter(use_agc_limiter);
+
+  return apm;
+}
+}  // namespace
+
+void FuzzOneInput(const uint8_t* data, size_t size) {
+  test::FuzzDataHelper fuzz_data(rtc::ArrayView<const uint8_t>(data, size));
+  auto apm = CreateApm(&fuzz_data);
+
+  if (apm) {
+    FuzzAudioProcessing(&fuzz_data, std::move(apm));
+  }
+}
+}  // namespace webrtc
diff --git a/test/fuzzers/audio_processing_fuzzer.cc b/test/fuzzers/audio_processing_fuzzer.cc
deleted file mode 100644
index a44d446..0000000
--- a/test/fuzzers/audio_processing_fuzzer.cc
+++ /dev/null
@@ -1,156 +0,0 @@
-/*
- *  Copyright (c) 2017 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 "test/fuzzers/audio_processing_fuzzer.h"
-
-#include <algorithm>
-#include <array>
-#include <cmath>
-
-#include "modules/audio_processing/include/audio_processing.h"
-#include "modules/include/module_common_types.h"
-#include "rtc_base/checks.h"
-
-namespace webrtc {
-namespace {
-size_t ByteToNativeRate(uint8_t data) {
-  using Rate = AudioProcessing::NativeRate;
-  switch (data % 4) {
-    case 0:
-      return static_cast<size_t>(Rate::kSampleRate8kHz);
-    case 1:
-      return static_cast<size_t>(Rate::kSampleRate16kHz);
-    case 2:
-      return static_cast<size_t>(Rate::kSampleRate32kHz);
-    default:
-      return static_cast<size_t>(Rate::kSampleRate48kHz);
-  }
-}
-
-template <class T>
-bool ParseSequence(size_t size,
-                   const uint8_t** data,
-                   size_t* remaining_size,
-                   T* result_data) {
-  const size_t data_size_bytes = sizeof(T) * size;
-  if (data_size_bytes > *remaining_size) {
-    return false;
-  }
-
-  std::copy(*data, *data + data_size_bytes,
-            reinterpret_cast<uint8_t*>(result_data));
-
-  *data += data_size_bytes;
-  *remaining_size -= data_size_bytes;
-  return true;
-}
-
-void FuzzAudioProcessing(const uint8_t* data,
-                         size_t size,
-                         bool is_float,
-                         AudioProcessing* apm) {
-  AudioFrame fixed_frame;
-  std::array<float, 480> float_frame{};
-  float* const first_channel = &float_frame[0];
-
-  while (size > 0) {
-    // Decide input/output rate for this iteration.
-    const auto input_rate_byte = ParseByte(&data, &size);
-    const auto output_rate_byte = ParseByte(&data, &size);
-    if (!input_rate_byte || !output_rate_byte) {
-      return;
-    }
-    const auto input_rate_hz = ByteToNativeRate(*input_rate_byte);
-    const auto output_rate_hz = ByteToNativeRate(*output_rate_byte);
-
-    const size_t samples_per_input_channel =
-        rtc::CheckedDivExact(input_rate_hz, 100ul);
-    fixed_frame.samples_per_channel_ = samples_per_input_channel;
-    fixed_frame.sample_rate_hz_ = input_rate_hz;
-
-    // Two channels breaks AEC3.
-    fixed_frame.num_channels_ = 1;
-
-    // Fill the arrays with audio samples from the data.
-    if (is_float) {
-      if (!ParseSequence(samples_per_input_channel, &data, &size,
-                         &float_frame[0])) {
-        return;
-      }
-    } else if (!ParseSequence(samples_per_input_channel, &data, &size,
-                              fixed_frame.mutable_data())) {
-      return;
-    }
-
-    // Filter obviously wrong values like inf/nan and values that will
-    // lead to inf/nan in calculations. 1e6 leads to DCHECKS failing.
-    for (auto& x : float_frame) {
-      if (!std::isnormal(x) || std::abs(x) > 1e5) {
-        x = 0;
-      }
-    }
-
-    // Make the APM call depending on capture/render mode and float /
-    // fix interface.
-    const auto is_capture = ParseBool(&data, &size);
-    if (!is_capture) {
-      return;
-    }
-    if (*is_capture) {
-      auto apm_return_code =
-          is_float ? (apm->ProcessStream(
-                         &first_channel, StreamConfig(input_rate_hz, 1),
-                         StreamConfig(output_rate_hz, 1), &first_channel))
-                   : (apm->ProcessStream(&fixed_frame));
-      RTC_DCHECK_NE(apm_return_code, AudioProcessing::kBadDataLengthError);
-    } else {
-      auto apm_return_code =
-          is_float ? (apm->ProcessReverseStream(
-                         &first_channel, StreamConfig(input_rate_hz, 1),
-                         StreamConfig(output_rate_hz, 1), &first_channel))
-                   : (apm->ProcessReverseStream(&fixed_frame));
-      RTC_DCHECK_NE(apm_return_code, AudioProcessing::kBadDataLengthError);
-    }
-  }
-}
-
-}  // namespace
-
-rtc::Optional<bool> ParseBool(const uint8_t** data, size_t* remaining_size) {
-  if (1 > *remaining_size) {
-    return rtc::nullopt;
-  }
-  auto res = (**data) % 2;
-  *data += 1;
-  *remaining_size -= 1;
-  return res;
-}
-
-rtc::Optional<uint8_t> ParseByte(const uint8_t** data, size_t* remaining_size) {
-  if (1 > *remaining_size) {
-    return rtc::nullopt;
-  }
-  auto res = **data;
-  *data += 1;
-  *remaining_size -= 1;
-  return res;
-}
-
-void FuzzAudioProcessing(const uint8_t* data,
-                         size_t size,
-                         std::unique_ptr<AudioProcessing> apm) {
-  const auto is_float = ParseBool(&data, &size);
-  if (!is_float) {
-    return;
-  }
-
-  FuzzAudioProcessing(data, size, *is_float, apm.get());
-}
-}  // namespace webrtc
diff --git a/test/fuzzers/audio_processing_fuzzer_configs.cc b/test/fuzzers/audio_processing_fuzzer_configs.cc
deleted file mode 100644
index 2e0a540..0000000
--- a/test/fuzzers/audio_processing_fuzzer_configs.cc
+++ /dev/null
@@ -1,101 +0,0 @@
-/*
- *  Copyright (c) 2017 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 "modules/audio_processing/include/audio_processing.h"
-#include "test/fuzzers/audio_processing_fuzzer.h"
-
-#include "api/optional.h"
-
-namespace webrtc {
-
-std::unique_ptr<AudioProcessing> CreateAPM(const uint8_t** data,
-                                           size_t* remaining_size) {
-  // Parse boolean values for optionally enabling different
-  // configurable public components of APM.
-  auto exp_agc = ParseBool(data, remaining_size);
-  auto exp_ns = ParseBool(data, remaining_size);
-  auto bf = ParseBool(data, remaining_size);
-  auto ef = ParseBool(data, remaining_size);
-  auto raf = ParseBool(data, remaining_size);
-  auto da = ParseBool(data, remaining_size);
-  auto ie = ParseBool(data, remaining_size);
-  auto red = ParseBool(data, remaining_size);
-  auto lc = ParseBool(data, remaining_size);
-  auto hpf = ParseBool(data, remaining_size);
-  auto aec3 = ParseBool(data, remaining_size);
-
-  auto use_aec = ParseBool(data, remaining_size);
-  auto use_aecm = ParseBool(data, remaining_size);
-  auto use_agc = ParseBool(data, remaining_size);
-  auto use_ns = ParseBool(data, remaining_size);
-  auto use_le = ParseBool(data, remaining_size);
-  auto use_vad = ParseBool(data, remaining_size);
-  auto use_agc_limiter = ParseBool(data, remaining_size);
-
-  if (!(exp_agc && exp_ns && bf && ef && raf && da && ie && red && lc && hpf &&
-        aec3 && use_aec && use_aecm && use_agc && use_ns && use_le && use_vad &&
-        use_agc_limiter)) {
-    return nullptr;
-  }
-
-  // Filter out incompatible settings that lead to CHECK failures.
-  if (*use_aecm && *use_aec) {
-    return nullptr;
-  }
-
-  // Components can be enabled through webrtc::Config and
-  // webrtc::AudioProcessingConfig.
-  Config config;
-
-  std::unique_ptr<EchoControlFactory> echo_control_factory;
-  if (*aec3) {
-    echo_control_factory.reset(new EchoCanceller3Factory());
-  }
-
-  config.Set<ExperimentalAgc>(new ExperimentalAgc(*exp_agc));
-  config.Set<ExperimentalNs>(new ExperimentalNs(*exp_ns));
-  if (*bf) {
-    config.Set<Beamforming>(new Beamforming());
-  }
-  config.Set<ExtendedFilter>(new ExtendedFilter(*ef));
-  config.Set<RefinedAdaptiveFilter>(new RefinedAdaptiveFilter(*raf));
-  config.Set<DelayAgnostic>(new DelayAgnostic(*da));
-  config.Set<Intelligibility>(new Intelligibility(*ie));
-
-  std::unique_ptr<AudioProcessing> apm(
-      AudioProcessingBuilder()
-          .SetEchoControlFactory(std::move(echo_control_factory))
-          .Create(config));
-
-  webrtc::AudioProcessing::Config apm_config;
-  apm_config.residual_echo_detector.enabled = *red;
-  apm_config.level_controller.enabled = *lc;
-  apm_config.high_pass_filter.enabled = *hpf;
-
-  apm->ApplyConfig(apm_config);
-
-  apm->echo_cancellation()->Enable(*use_aec);
-  apm->echo_control_mobile()->Enable(*use_aecm);
-  apm->gain_control()->Enable(*use_agc);
-  apm->noise_suppression()->Enable(*use_ns);
-  apm->level_estimator()->Enable(*use_le);
-  apm->voice_detection()->Enable(*use_vad);
-  apm->gain_control()->enable_limiter(*use_agc_limiter);
-
-  return apm;
-}
-
-void FuzzOneInput(const uint8_t* data, size_t size) {
-  auto apm = CreateAPM(&data, &size);
-  if (apm) {
-    FuzzAudioProcessing(data, size, std::move(apm));
-  }
-}
-}  // namespace webrtc
diff --git a/test/fuzzers/audio_processing_fuzzer_helper.cc b/test/fuzzers/audio_processing_fuzzer_helper.cc
new file mode 100644
index 0000000..30a66ed
--- /dev/null
+++ b/test/fuzzers/audio_processing_fuzzer_helper.cc
@@ -0,0 +1,120 @@
+/*
+ *  Copyright (c) 2017 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 "test/fuzzers/audio_processing_fuzzer_helper.h"
+
+#include <algorithm>
+#include <array>
+#include <cmath>
+#include <limits>
+
+#include "modules/audio_processing/include/audio_processing.h"
+#include "modules/include/module_common_types.h"
+#include "rtc_base/checks.h"
+
+namespace webrtc {
+namespace {
+void GenerateFloatFrame(test::FuzzDataHelper* fuzz_data,
+                        size_t input_rate,
+                        size_t num_channels,
+                        float* const* float_frames) {
+  const size_t samples_per_input_channel =
+      rtc::CheckedDivExact(input_rate, 100ul);
+  RTC_DCHECK_LE(samples_per_input_channel, 480);
+  for (size_t i = 0; i < num_channels; ++i) {
+    for (size_t j = 0; j < samples_per_input_channel; ++j) {
+      float_frames[i][j] =
+          static_cast<float>(fuzz_data->ReadOrDefaultValue<int16_t>(0)) /
+          static_cast<float>(std::numeric_limits<int16_t>::max());
+    }
+  }
+}
+
+void GenerateFixedFrame(test::FuzzDataHelper* fuzz_data,
+                        size_t input_rate,
+                        size_t num_channels,
+                        AudioFrame* fixed_frame) {
+  const size_t samples_per_input_channel =
+      rtc::CheckedDivExact(input_rate, 100ul);
+  fixed_frame->samples_per_channel_ = samples_per_input_channel;
+  fixed_frame->sample_rate_hz_ = input_rate;
+  fixed_frame->num_channels_ = num_channels;
+
+  RTC_DCHECK_LE(samples_per_input_channel * num_channels,
+                AudioFrame::kMaxDataSizeSamples);
+  for (size_t i = 0; i < samples_per_input_channel * num_channels; ++i) {
+    fixed_frame->mutable_data()[i] = fuzz_data->ReadOrDefaultValue(0);
+  }
+}
+}  // namespace
+
+void FuzzAudioProcessing(test::FuzzDataHelper* fuzz_data,
+                         std::unique_ptr<AudioProcessing> apm) {
+  AudioFrame fixed_frame;
+  std::array<float, 480> float_frame1;
+  std::array<float, 480> float_frame2;
+  std::array<float* const, 2> float_frame_ptrs = {
+      &float_frame1[0], &float_frame2[0],
+  };
+  float* const* ptr_to_float_frames = &float_frame_ptrs[0];
+
+  using Rate = AudioProcessing::NativeRate;
+  const Rate rate_kinds[] = {Rate::kSampleRate8kHz, Rate::kSampleRate16kHz,
+                             Rate::kSampleRate32kHz, Rate::kSampleRate48kHz};
+
+  // We may run out of fuzz data in the middle of a loop iteration. In
+  // that case, default values will be used for the rest of that
+  // iteration.
+  while (fuzz_data->CanReadBytes(1)) {
+    const bool is_float = fuzz_data->ReadOrDefaultValue(true);
+    // Decide input/output rate for this iteration.
+    const auto input_rate =
+        static_cast<size_t>(fuzz_data->SelectOneOf(rate_kinds));
+    const auto output_rate =
+        static_cast<size_t>(fuzz_data->SelectOneOf(rate_kinds));
+
+    const bool num_channels = fuzz_data->ReadOrDefaultValue(true) ? 2 : 1;
+    const uint8_t stream_delay = fuzz_data->ReadOrDefaultValue(0);
+
+    // API call needed for AEC-2 and AEC-m to run.
+    apm->set_stream_delay_ms(stream_delay);
+
+    // Make the APM call depending on capture/render mode and float /
+    // fix interface.
+    const bool is_capture = fuzz_data->ReadOrDefaultValue(true);
+
+    // Fill the arrays with audio samples from the data.
+    int apm_return_code = AudioProcessing::Error::kNoError;
+    if (is_float) {
+      GenerateFloatFrame(fuzz_data, input_rate, num_channels,
+                         ptr_to_float_frames);
+      if (is_capture) {
+        apm_return_code = apm->ProcessStream(
+            ptr_to_float_frames, StreamConfig(input_rate, num_channels),
+            StreamConfig(output_rate, num_channels), ptr_to_float_frames);
+      } else {
+        apm_return_code = apm->ProcessReverseStream(
+            ptr_to_float_frames, StreamConfig(input_rate, 1),
+            StreamConfig(output_rate, 1), ptr_to_float_frames);
+      }
+    } else {
+      GenerateFixedFrame(fuzz_data, input_rate, num_channels, &fixed_frame);
+
+      if (is_capture) {
+        apm_return_code = apm->ProcessStream(&fixed_frame);
+      } else {
+        apm_return_code = apm->ProcessReverseStream(&fixed_frame);
+      }
+    }
+
+    RTC_DCHECK_NE(apm_return_code, AudioProcessing::kBadDataLengthError);
+  }
+}
+}  // namespace webrtc
diff --git a/test/fuzzers/audio_processing_fuzzer.h b/test/fuzzers/audio_processing_fuzzer_helper.h
similarity index 60%
rename from test/fuzzers/audio_processing_fuzzer.h
rename to test/fuzzers/audio_processing_fuzzer_helper.h
index 337d9b2..697ed8d 100644
--- a/test/fuzzers/audio_processing_fuzzer.h
+++ b/test/fuzzers/audio_processing_fuzzer_helper.h
@@ -8,20 +8,18 @@
  *  be found in the AUTHORS file in the root of the source tree.
  */
 
-#ifndef TEST_FUZZERS_AUDIO_PROCESSING_FUZZER_H_
-#define TEST_FUZZERS_AUDIO_PROCESSING_FUZZER_H_
+#ifndef TEST_FUZZERS_AUDIO_PROCESSING_FUZZER_HELPER_H_
+#define TEST_FUZZERS_AUDIO_PROCESSING_FUZZER_HELPER_H_
 
 #include <memory>
 
 #include "modules/audio_processing/include/audio_processing.h"
+#include "test/fuzzers/fuzz_data_helper.h"
 namespace webrtc {
 
-rtc::Optional<bool> ParseBool(const uint8_t** data, size_t* remaining_size);
-rtc::Optional<uint8_t> ParseByte(const uint8_t** data, size_t* remaining_size);
-
-void FuzzAudioProcessing(const uint8_t* data,
-                         size_t size,
+void FuzzAudioProcessing(test::FuzzDataHelper* fuzz_data,
                          std::unique_ptr<AudioProcessing> apm);
+
 }  // namespace webrtc
 
-#endif  // TEST_FUZZERS_AUDIO_PROCESSING_FUZZER_H_
+#endif  // TEST_FUZZERS_AUDIO_PROCESSING_FUZZER_HELPER_H_