Add the Ooura FFT to RealFourier.

We are using the Ooura FFT in a few places:
- AGC
- Transient suppression
- Noise suppression

The optimized OpenMAX DL FFT is considerably faster, but currently does
not compile everywhere, notably on iOS. This change will allow us to use
Openmax when possible and otherwise fall back to Ooura.

(Unfortunately, noise suppression won't be able to take advantage of it
since it's not C++. Upgrade time?)

R=aluebs@webrtc.org, mgraczyk@chromium.org

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

Cr-Commit-Position: refs/heads/master@{#8798}
git-svn-id: http://webrtc.googlecode.com/svn/trunk@8798 4adac7df-926f-26a2-2b94-8c16560cd09d
diff --git a/webrtc/LICENSE_THIRD_PARTY b/webrtc/LICENSE_THIRD_PARTY
index bd47730..b64dbba 100644
--- a/webrtc/LICENSE_THIRD_PARTY
+++ b/webrtc/LICENSE_THIRD_PARTY
@@ -2,6 +2,7 @@
 party licenses. Paths to the files and associated licenses are collected here.
 
 Files governed by third party licenses:
+common_audio/fft4g.c
 common_audio/signal_processing/spl_sqrt_floor.c
 common_audio/signal_processing/spl_sqrt_floor_arm.S
 modules/audio_coding/codecs/g711/main/source/g711.c
@@ -14,8 +15,6 @@
 modules/audio_device/mac/portaudio/pa_ringbuffer.c
 modules/audio_device/mac/portaudio/pa_ringbuffer.h
 modules/audio_processing/aec/aec_rdft.c
-modules/audio_processing/utility/fft4g.c
-base/scoped_ptr.h
 system_wrappers/source/condition_variable_event_win.cc
 system_wrappers/source/set_thread_name_win.h
 system_wrappers/source/spreadsortlib/constants.hpp
@@ -231,8 +230,8 @@
  */
 -------------------------------------------------------------------------------
 Files:
+common_audio/fft4g.c
 modules/audio_processing/aec/aec_rdft.c
-modules/audio_processing/utility/fft4g.c
 
 License:
 /*
@@ -245,21 +244,6 @@
  */
 -------------------------------------------------------------------------------
 Files:
-base/scoped_ptr.h
-
-License:
-//  (C) Copyright Greg Colvin and Beman Dawes 1998, 1999.
-//  Copyright (c) 2001, 2002 Peter Dimov
-//
-//  Permission to copy, use, modify, sell and distribute this software
-//  is granted provided this copyright notice appears in all copies.
-//  This software is provided "as is" without express or implied
-//  warranty, and with no claim as to its suitability for any purpose.
-//
-//  See http://www.boost.org/libs/smart_ptr/scoped_ptr.htm for documentation.
-//
--------------------------------------------------------------------------------
-Files:
 system_wrappers/source/condition_variable_event_win.cc
 
 Source:
diff --git a/webrtc/common_audio/BUILD.gn b/webrtc/common_audio/BUILD.gn
index c9c3c5b..34e1575 100644
--- a/webrtc/common_audio/BUILD.gn
+++ b/webrtc/common_audio/BUILD.gn
@@ -19,8 +19,6 @@
 
 source_set("common_audio") {
   sources = [
-    "channel_buffer.cc",
-    "channel_buffer.h",
     "audio_converter.cc",
     "audio_converter.h",
     "audio_ring_buffer.cc",
@@ -28,11 +26,21 @@
     "audio_util.cc",
     "blocker.cc",
     "blocker.h",
+    "channel_buffer.cc",
+    "channel_buffer.h",
+    "fft4g.c",
+    "fft4g.h",
     "fir_filter.cc",
     "fir_filter.h",
     "fir_filter_neon.h",
     "fir_filter_sse.h",
     "include/audio_util.h",
+    "lapped_transform.cc",
+    "lapped_transform.h",
+    "real_fourier.cc",
+    "real_fourier.h",
+    "real_fourier_ooura.cc",
+    "real_fourier_ooura.h",
     "resampler/include/push_resampler.h",
     "resampler/include/resampler.h",
     "resampler/push_resampler.cc",
@@ -99,14 +107,13 @@
 
   deps = [ "../system_wrappers" ]
 
+  defines = []
   if (rtc_use_openmax_dl) {
     sources += [
-      "lapped_transform.cc",
-      "lapped_transform.h",
-      "real_fourier.cc",
-      "real_fourier.h",
+      "real_fourier_openmax.cc",
+      "real_fourier_openmax.h",
     ]
-
+    defines += [ "RTC_USE_OPENMAX_DL" ]
     deps += [ "//third_party/openmax_dl/dl" ]
   }
 
diff --git a/webrtc/common_audio/common_audio.gyp b/webrtc/common_audio/common_audio.gyp
index 3ea336c..e28f4b0 100644
--- a/webrtc/common_audio/common_audio.gyp
+++ b/webrtc/common_audio/common_audio.gyp
@@ -29,8 +29,6 @@
         ],
       },
       'sources': [
-        'channel_buffer.cc',
-        'channel_buffer.h',
         'audio_converter.cc',
         'audio_converter.h',
         'audio_ring_buffer.cc',
@@ -38,11 +36,21 @@
         'audio_util.cc',
         'blocker.cc',
         'blocker.h',
+        'channel_buffer.cc',
+        'channel_buffer.h',
+        'fft4g.c',
+        'fft4g.h',
         'fir_filter.cc',
         'fir_filter.h',
         'fir_filter_neon.h',
         'fir_filter_sse.h',
         'include/audio_util.h',
+        'lapped_transform.cc',
+        'lapped_transform.h',
+        'real_fourier.cc',
+        'real_fourier.h',
+        'real_fourier_ooura.cc',
+        'real_fourier_ooura.h',
         'resampler/include/push_resampler.h',
         'resampler/include/resampler.h',
         'resampler/push_resampler.cc',
@@ -113,11 +121,10 @@
       'conditions': [
         ['rtc_use_openmax_dl==1', {
           'sources': [
-            'lapped_transform.cc',
-            'lapped_transform.h',
-            'real_fourier.cc',
-            'real_fourier.h',
+            'real_fourier_openmax.cc',
+            'real_fourier_openmax.h',
           ],
+          'defines': ['RTC_USE_OPENMAX_DL',],
           'conditions': [
             ['build_openmax_dl==1', {
               'dependencies': ['<(DEPTH)/third_party/openmax_dl/dl/dl.gyp:openmax_dl',],
@@ -241,6 +248,8 @@
             'audio_util_unittest.cc',
             'blocker_unittest.cc',
             'fir_filter_unittest.cc',
+            'lapped_transform_unittest.cc',
+            'real_fourier_unittest.cc',
             'resampler/resampler_unittest.cc',
             'resampler/push_resampler_unittest.cc',
             'resampler/push_sinc_resampler_unittest.cc',
@@ -262,10 +271,7 @@
           ],
           'conditions': [
             ['rtc_use_openmax_dl==1', {
-              'sources': [
-                'lapped_transform_unittest.cc',
-                'real_fourier_unittest.cc',
-              ],
+              'defines': ['RTC_USE_OPENMAX_DL',],
             }],
             ['OS=="android"', {
               'dependencies': [
diff --git a/webrtc/modules/audio_processing/utility/fft4g.c b/webrtc/common_audio/fft4g.c
similarity index 100%
rename from webrtc/modules/audio_processing/utility/fft4g.c
rename to webrtc/common_audio/fft4g.c
diff --git a/webrtc/common_audio/fft4g.h b/webrtc/common_audio/fft4g.h
new file mode 100644
index 0000000..90fefa0
--- /dev/null
+++ b/webrtc/common_audio/fft4g.h
@@ -0,0 +1,26 @@
+/*
+ *  Copyright (c) 2011 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_COMMON_AUDIO_FFT4G_H_
+#define WEBRTC_COMMON_AUDIO_FFT4G_H_
+
+#if defined(__cplusplus)
+extern "C" {
+#endif
+
+// Refer to fft4g.c for documentation.
+void WebRtc_rdft(int n, int isgn, float *a, int *ip, float *w);
+void WebRtc_cdft(int n, int isgn, float *a, int *ip, float *w);
+
+#if defined(__cplusplus)
+}
+#endif
+
+#endif  // WEBRTC_COMMON_AUDIO_FFT4G_H_
diff --git a/webrtc/common_audio/lapped_transform.cc b/webrtc/common_audio/lapped_transform.cc
index 6b4f135..3883582 100644
--- a/webrtc/common_audio/lapped_transform.cc
+++ b/webrtc/common_audio/lapped_transform.cc
@@ -31,7 +31,8 @@
   for (int i = 0; i < num_input_channels; ++i) {
     memcpy(parent_->real_buf_.Row(i), input[i],
            num_frames * sizeof(*input[0]));
-    parent_->fft_.Forward(parent_->real_buf_.Row(i), parent_->cplx_pre_.Row(i));
+    parent_->fft_->Forward(parent_->real_buf_.Row(i),
+                           parent_->cplx_pre_.Row(i));
   }
 
   int block_length = RealFourier::ComplexLength(
@@ -44,8 +45,8 @@
                                                parent_->cplx_post_.Array());
 
   for (int i = 0; i < num_output_channels; ++i) {
-    parent_->fft_.Inverse(parent_->cplx_post_.Row(i),
-                          parent_->real_buf_.Row(i));
+    parent_->fft_->Inverse(parent_->cplx_post_.Row(i),
+                           parent_->real_buf_.Row(i));
     memcpy(output[i], parent_->real_buf_.Row(i),
            num_frames * sizeof(*input[0]));
   }
@@ -64,8 +65,8 @@
       blocker_(
         chunk_length_, block_length_, in_channels_, out_channels_, window,
         shift_amount, &blocker_callback_),
-      fft_(RealFourier::FftOrder(block_length_)),
-      cplx_length_(RealFourier::ComplexLength(fft_.order())),
+      fft_(RealFourier::Create(RealFourier::FftOrder(block_length_))),
+      cplx_length_(RealFourier::ComplexLength(fft_->order())),
       real_buf_(in_channels, block_length_, RealFourier::kFftBufferAlignment),
       cplx_pre_(in_channels, cplx_length_, RealFourier::kFftBufferAlignment),
       cplx_post_(out_channels, cplx_length_, RealFourier::kFftBufferAlignment) {
@@ -81,7 +82,7 @@
 void LappedTransform::ProcessChunk(const float* const* in_chunk,
                                    float* const* out_chunk) {
   blocker_.ProcessChunk(in_chunk, chunk_length_, in_channels_, out_channels_,
-                         out_chunk);
+                        out_chunk);
 }
 
 }  // namespace webrtc
diff --git a/webrtc/common_audio/lapped_transform.h b/webrtc/common_audio/lapped_transform.h
index f4124b8..3ed9528 100644
--- a/webrtc/common_audio/lapped_transform.h
+++ b/webrtc/common_audio/lapped_transform.h
@@ -82,7 +82,7 @@
   Callback* const block_processor_;
   Blocker blocker_;
 
-  RealFourier fft_;
+  rtc::scoped_ptr<RealFourier> fft_;
   const int cplx_length_;
   AlignedArray<float> real_buf_;
   AlignedArray<std::complex<float> > cplx_pre_;
diff --git a/webrtc/common_audio/real_fourier.cc b/webrtc/common_audio/real_fourier.cc
index 81fd45c..dec2be6 100644
--- a/webrtc/common_audio/real_fourier.cc
+++ b/webrtc/common_audio/real_fourier.cc
@@ -10,54 +10,37 @@
 
 #include "webrtc/common_audio/real_fourier.h"
 
-#include <cstdlib>
-
-#include "dl/sp/api/omxSP.h"
 #include "webrtc/base/checks.h"
+#include "webrtc/common_audio/real_fourier_ooura.h"
+#include "webrtc/common_audio/real_fourier_openmax.h"
+#include "webrtc/common_audio/signal_processing/include/spl_inl.h"
 
 namespace webrtc {
 
 using std::complex;
 
-// The omx implementation uses this macro to check order validity.
-const int RealFourier::kMaxFftOrder = TWIDDLE_TABLE_ORDER;
 const int RealFourier::kFftBufferAlignment = 32;
 
-RealFourier::RealFourier(int fft_order)
-    : order_(fft_order),
-      omx_spec_(nullptr) {
-  CHECK_GE(order_, 1);
-  CHECK_LE(order_, kMaxFftOrder);
-
-  OMX_INT buffer_size;
-  OMXResult r;
-
-  r = omxSP_FFTGetBufSize_R_F32(order_, &buffer_size);
-  CHECK_EQ(r, OMX_Sts_NoErr);
-
-  omx_spec_ = malloc(buffer_size);
-  DCHECK(omx_spec_);
-
-  r = omxSP_FFTInit_R_F32(omx_spec_, order_);
-  CHECK_EQ(r, OMX_Sts_NoErr);
-}
-
-RealFourier::~RealFourier() {
-  free(omx_spec_);
+rtc::scoped_ptr<RealFourier> RealFourier::Create(int fft_order) {
+#if defined(RTC_USE_OPENMAX_DL)
+  return rtc::scoped_ptr<RealFourier>(new RealFourierOpenmax(fft_order));
+#else
+  return rtc::scoped_ptr<RealFourier>(new RealFourierOoura(fft_order));
+#endif
 }
 
 int RealFourier::FftOrder(int length) {
-  for (int order = 0; order <= kMaxFftOrder; order++) {
-    if ((1 << order) >= length) {
-      return order;
-    }
-  }
-  return -1;
+  CHECK_GT(length, 0);
+  return WebRtcSpl_GetSizeInBits(length - 1);
+}
+
+int RealFourier::FftLength(int order) {
+  CHECK_GE(order, 0);
+  return 1 << order;
 }
 
 int RealFourier::ComplexLength(int order) {
-  CHECK_LE(order, kMaxFftOrder);
-  CHECK_GT(order, 0);
+  CHECK_GE(order, 0);
   return (1 << order) / 2 + 1;
 }
 
@@ -71,18 +54,5 @@
       AlignedMalloc(sizeof(complex<float>) * count, kFftBufferAlignment)));
 }
 
-void RealFourier::Forward(const float* src, complex<float>* dest) const {
-  OMXResult r;
-  r = omxSP_FFTFwd_RToCCS_F32(src, reinterpret_cast<OMX_F32*>(dest), omx_spec_);
-  CHECK_EQ(r, OMX_Sts_NoErr);
-}
-
-void RealFourier::Inverse(const complex<float>* src, float* dest) const {
-  OMXResult r;
-  r = omxSP_FFTInv_CCSToR_F32(reinterpret_cast<const OMX_F32*>(src), dest,
-                              omx_spec_);
-  CHECK_EQ(r, OMX_Sts_NoErr);
-}
-
 }  // namespace webrtc
 
diff --git a/webrtc/common_audio/real_fourier.h b/webrtc/common_audio/real_fourier.h
index eda3ba3..cc49dbf 100644
--- a/webrtc/common_audio/real_fourier.h
+++ b/webrtc/common_audio/real_fourier.h
@@ -29,24 +29,23 @@
   typedef rtc::scoped_ptr<std::complex<float>[], AlignedFreeDeleter>
       fft_cplx_scoper;
 
-  // The maximum input order supported by this implementation.
-  static const int kMaxFftOrder;
-
   // The alignment required for all input and output buffers, in bytes.
   static const int kFftBufferAlignment;
 
   // Construct a wrapper instance for the given input order, which must be
   // between 1 and kMaxFftOrder, inclusively.
-  explicit RealFourier(int fft_order);
-  ~RealFourier();
+  static rtc::scoped_ptr<RealFourier> Create(int fft_order);
+  virtual ~RealFourier() {};
 
-  // Short helper to compute the smallest FFT order (a power of 2) which will
-  // contain the given input length. Returns -1 if the order would have been
-  // too big for the implementation.
+  // Helper to compute the smallest FFT order (a power of 2) which will contain
+  // the given input length.
   static int FftOrder(int length);
 
-  // Short helper to compute the exact length, in complex floats, of the
-  // transform output (i.e. |2^order / 2 + 1|).
+  // Helper to compute the input length from the FFT order.
+  static int FftLength(int order);
+
+  // Helper to compute the exact length, in complex floats, of the transform
+  // output (i.e. |2^order / 2 + 1|).
   static int ComplexLength(int order);
 
   // Buffer allocation helpers. The buffers are large enough to hold |count|
@@ -61,23 +60,13 @@
   // returned. Input and output must be properly aligned (e.g. through
   // AllocRealBuffer and AllocCplxBuffer) and input length must be
   // |2^order| (same as given at construction time).
-  void Forward(const float* src, std::complex<float>* dest) const;
+  virtual void Forward(const float* src, std::complex<float>* dest) const = 0;
 
   // Inverse transform. Same input format as output above, conjugate pairs
   // not needed.
-  void Inverse(const std::complex<float>* src, float* dest) const;
+  virtual void Inverse(const std::complex<float>* src, float* dest) const = 0;
 
-  int order() const {
-    return order_;
-  }
-
- private:
-  // Basically a forward declare of OMXFFTSpec_R_F32. To get rid of the
-  // dependency on openmax.
-  typedef void OMXFFTSpec_R_F32_;
-  const int order_;
-
-  OMXFFTSpec_R_F32_* omx_spec_;
+  virtual int order() const = 0;
 };
 
 }  // namespace webrtc
diff --git a/webrtc/common_audio/real_fourier_ooura.cc b/webrtc/common_audio/real_fourier_ooura.cc
new file mode 100644
index 0000000..6f76516
--- /dev/null
+++ b/webrtc/common_audio/real_fourier_ooura.cc
@@ -0,0 +1,85 @@
+/*
+ *  Copyright (c) 2015 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/common_audio/real_fourier_ooura.h"
+
+#include <cmath>
+#include <algorithm>
+
+#include "webrtc/base/checks.h"
+#include "webrtc/common_audio/fft4g.h"
+
+namespace webrtc {
+
+using std::complex;
+
+namespace {
+
+void Conjugate(complex<float>* array, int complex_length) {
+  std::for_each(array, array + complex_length,
+                [=](complex<float>& v) { v = std::conj(v); });
+}
+
+size_t ComputeWorkIpSize(int fft_length) {
+  return static_cast<size_t>(2 + std::ceil(std::sqrt(
+      static_cast<float>(fft_length))));
+}
+
+}  // namespace
+
+RealFourierOoura::RealFourierOoura(int fft_order)
+    : order_(fft_order),
+      length_(FftLength(order_)),
+      complex_length_(ComplexLength(order_)),
+      // Zero-initializing work_ip_ will cause rdft to initialize these work
+      // arrays on the first call.
+      work_ip_(new int[ComputeWorkIpSize(length_)]()),
+      work_w_(new float[complex_length_]()) {
+  CHECK_GE(fft_order, 1);
+}
+
+void RealFourierOoura::Forward(const float* src, complex<float>* dest) const {
+  {
+    // This cast is well-defined since C++11. See "Non-static data members" at:
+    // http://en.cppreference.com/w/cpp/numeric/complex
+    auto dest_float = reinterpret_cast<float*>(dest);
+    std::copy(src, src + length_, dest_float);
+    WebRtc_rdft(length_, 1, dest_float, work_ip_.get(), work_w_.get());
+  }
+
+  // Ooura places real[n/2] in imag[0].
+  dest[complex_length_ - 1] = complex<float>(dest[0].imag(), 0.0f);
+  dest[0] = complex<float>(dest[0].real(), 0.0f);
+  // Ooura returns the conjugate of the usual Fourier definition.
+  Conjugate(dest, complex_length_);
+}
+
+void RealFourierOoura::Inverse(const complex<float>* src, float* dest) const {
+  {
+    auto dest_complex = reinterpret_cast<complex<float>*>(dest);
+    // The real output array is shorter than the input complex array by one
+    // complex element.
+    const int dest_complex_length = complex_length_ - 1;
+    std::copy(src, src + dest_complex_length, dest_complex);
+    // Restore Ooura's conjugate definition.
+    Conjugate(dest_complex, dest_complex_length);
+    // Restore real[n/2] to imag[0].
+    dest_complex[0] = complex<float>(dest_complex[0].real(),
+                                     src[complex_length_ - 1].real());
+  }
+
+  WebRtc_rdft(length_, -1, dest, work_ip_.get(), work_w_.get());
+
+  // Ooura returns a scaled version.
+  const float scale = 2.0f / length_;
+  std::for_each(dest, dest + length_, [scale](float& v) { v *= scale; });
+}
+
+}  // namespace webrtc
diff --git a/webrtc/common_audio/real_fourier_ooura.h b/webrtc/common_audio/real_fourier_ooura.h
new file mode 100644
index 0000000..67b3ffd
--- /dev/null
+++ b/webrtc/common_audio/real_fourier_ooura.h
@@ -0,0 +1,45 @@
+/*
+ *  Copyright (c) 2015 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_COMMON_AUDIO_REAL_FOURIER_OOURA_H_
+#define WEBRTC_COMMON_AUDIO_REAL_FOURIER_OOURA_H_
+
+#include <complex>
+
+#include "webrtc/base/scoped_ptr.h"
+#include "webrtc/common_audio/real_fourier.h"
+
+namespace webrtc {
+
+class RealFourierOoura : public RealFourier {
+ public:
+  explicit RealFourierOoura(int fft_order);
+
+  void Forward(const float* src, std::complex<float>* dest) const override;
+  void Inverse(const std::complex<float>* src, float* dest) const override;
+
+  int order() const override {
+    return order_;
+  }
+
+ private:
+  const int order_;
+  const int length_;
+  const int complex_length_;
+  // These are work arrays for Ooura. The names are based on the comments in
+  // fft4g.c.
+  const rtc::scoped_ptr<int[]> work_ip_;
+  const rtc::scoped_ptr<float[]> work_w_;
+};
+
+}  // namespace webrtc
+
+#endif  // WEBRTC_COMMON_AUDIO_REAL_FOURIER_OOURA_H_
+
diff --git a/webrtc/common_audio/real_fourier_openmax.cc b/webrtc/common_audio/real_fourier_openmax.cc
new file mode 100644
index 0000000..f7a0f64
--- /dev/null
+++ b/webrtc/common_audio/real_fourier_openmax.cc
@@ -0,0 +1,69 @@
+/*
+ *  Copyright (c) 2015 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/common_audio/real_fourier_openmax.h"
+
+#include <cstdlib>
+
+#include "dl/sp/api/omxSP.h"
+#include "webrtc/base/checks.h"
+
+namespace webrtc {
+
+using std::complex;
+
+namespace {
+
+// Creates and initializes the Openmax state. Transfers ownership to caller.
+OMXFFTSpec_R_F32* CreateOpenmaxState(int order) {
+  CHECK_GE(order, 1);
+  // The omx implementation uses this macro to check order validity.
+  CHECK_LE(order, TWIDDLE_TABLE_ORDER);
+
+  OMX_INT buffer_size;
+  OMXResult r = omxSP_FFTGetBufSize_R_F32(order, &buffer_size);
+  CHECK_EQ(r, OMX_Sts_NoErr);
+
+  OMXFFTSpec_R_F32* omx_spec = malloc(buffer_size);
+  DCHECK(omx_spec);
+
+  r = omxSP_FFTInit_R_F32(omx_spec, order);
+  CHECK_EQ(r, OMX_Sts_NoErr);
+  return omx_spec;
+}
+
+}  // namespace
+
+RealFourierOpenmax::RealFourierOpenmax(int fft_order)
+    : order_(fft_order),
+      omx_spec_(CreateOpenmaxState(order_)) {
+}
+
+RealFourierOpenmax::~RealFourierOpenmax() {
+  free(omx_spec_);
+}
+
+void RealFourierOpenmax::Forward(const float* src, complex<float>* dest) const {
+  // This cast is well-defined since C++11. See "Non-static data members" at:
+  // http://en.cppreference.com/w/cpp/numeric/complex
+  OMXResult r =
+      omxSP_FFTFwd_RToCCS_F32(src, reinterpret_cast<OMX_F32*>(dest), omx_spec_);
+  CHECK_EQ(r, OMX_Sts_NoErr);
+}
+
+void RealFourierOpenmax::Inverse(const complex<float>* src, float* dest) const {
+  OMXResult r =
+      omxSP_FFTInv_CCSToR_F32(reinterpret_cast<const OMX_F32*>(src), dest,
+                              omx_spec_);
+  CHECK_EQ(r, OMX_Sts_NoErr);
+}
+
+}  // namespace webrtc
+
diff --git a/webrtc/common_audio/real_fourier_openmax.h b/webrtc/common_audio/real_fourier_openmax.h
new file mode 100644
index 0000000..63ce5ba
--- /dev/null
+++ b/webrtc/common_audio/real_fourier_openmax.h
@@ -0,0 +1,44 @@
+/*
+ *  Copyright (c) 2015 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_COMMON_AUDIO_REAL_FOURIER_OPENMAX_H_
+#define WEBRTC_COMMON_AUDIO_REAL_FOURIER_OPENMAX_H_
+
+#include <complex>
+
+#include "webrtc/common_audio/real_fourier.h"
+
+namespace webrtc {
+
+class RealFourierOpenmax : public RealFourier {
+ public:
+  explicit RealFourierOpenmax(int fft_order);
+  ~RealFourierOpenmax() override;
+
+  void Forward(const float* src, std::complex<float>* dest) const override;
+  void Inverse(const std::complex<float>* src, float* dest) const override;
+
+  int order() const override {
+    return order_;
+  }
+
+ private:
+  // Basically a forward declare of OMXFFTSpec_R_F32. To get rid of the
+  // dependency on openmax.
+  typedef void OMXFFTSpec_R_F32_;
+  const int order_;
+
+  OMXFFTSpec_R_F32_* const omx_spec_;
+};
+
+}  // namespace webrtc
+
+#endif  // WEBRTC_COMMON_AUDIO_REAL_FOURIER_OPENMAX_H_
+
diff --git a/webrtc/common_audio/real_fourier_unittest.cc b/webrtc/common_audio/real_fourier_unittest.cc
index 8660d4d..a663441 100644
--- a/webrtc/common_audio/real_fourier_unittest.cc
+++ b/webrtc/common_audio/real_fourier_unittest.cc
@@ -13,6 +13,9 @@
 #include <stdlib.h>
 
 #include "testing/gtest/include/gtest/gtest.h"
+#include "webrtc/base/scoped_ptr.h"
+#include "webrtc/common_audio/real_fourier_openmax.h"
+#include "webrtc/common_audio/real_fourier_ooura.h"
 
 namespace webrtc {
 
@@ -24,81 +27,83 @@
     real = RealFourier::AllocRealBuffer(3);
     ASSERT_TRUE(real.get() != nullptr);
     int64_t ptr_value = reinterpret_cast<int64_t>(real.get());
-    ASSERT_EQ(ptr_value % RealFourier::kFftBufferAlignment, 0);
+    EXPECT_EQ(ptr_value % RealFourier::kFftBufferAlignment, 0);
   }
   {
     RealFourier::fft_cplx_scoper cplx;
     cplx = RealFourier::AllocCplxBuffer(3);
     ASSERT_TRUE(cplx.get() != nullptr);
     int64_t ptr_value = reinterpret_cast<int64_t>(cplx.get());
-    ASSERT_EQ(ptr_value % RealFourier::kFftBufferAlignment, 0);
+    EXPECT_EQ(ptr_value % RealFourier::kFftBufferAlignment, 0);
   }
 }
 
 TEST(RealFourierStaticsTest, OrderComputation) {
-  ASSERT_EQ(RealFourier::FftOrder(2000000), -1);
-  ASSERT_EQ(RealFourier::FftOrder((1 << RealFourier::kMaxFftOrder) + 1), -1);
-  ASSERT_EQ(RealFourier::FftOrder(1 << RealFourier::kMaxFftOrder),
-            RealFourier::kMaxFftOrder);
-  ASSERT_EQ(RealFourier::FftOrder(13), 4);
-  ASSERT_EQ(RealFourier::FftOrder(32), 5);
-  ASSERT_EQ(RealFourier::FftOrder(2), 1);
-  ASSERT_EQ(RealFourier::FftOrder(1), 0);
-  ASSERT_EQ(RealFourier::FftOrder(0), 0);
+  EXPECT_EQ(RealFourier::FftOrder(13), 4);
+  EXPECT_EQ(RealFourier::FftOrder(32), 5);
+  EXPECT_EQ(RealFourier::FftOrder(2), 1);
+  EXPECT_EQ(RealFourier::FftOrder(1), 0);
 }
 
 TEST(RealFourierStaticsTest, ComplexLengthComputation) {
-  ASSERT_EQ(RealFourier::ComplexLength(1), 2);
-  ASSERT_EQ(RealFourier::ComplexLength(2), 3);
-  ASSERT_EQ(RealFourier::ComplexLength(3), 5);
-  ASSERT_EQ(RealFourier::ComplexLength(4), 9);
-  ASSERT_EQ(RealFourier::ComplexLength(5), 17);
-  ASSERT_EQ(RealFourier::ComplexLength(7), 65);
+  EXPECT_EQ(RealFourier::ComplexLength(1), 2);
+  EXPECT_EQ(RealFourier::ComplexLength(2), 3);
+  EXPECT_EQ(RealFourier::ComplexLength(3), 5);
+  EXPECT_EQ(RealFourier::ComplexLength(4), 9);
+  EXPECT_EQ(RealFourier::ComplexLength(5), 17);
+  EXPECT_EQ(RealFourier::ComplexLength(7), 65);
 }
 
+template <typename T>
 class RealFourierTest : public ::testing::Test {
  protected:
   RealFourierTest()
-      : rf_(new RealFourier(2)),
+      : rf_(2),
         real_buffer_(RealFourier::AllocRealBuffer(4)),
         cplx_buffer_(RealFourier::AllocCplxBuffer(3)) {}
 
   ~RealFourierTest() {
-    delete rf_;
   }
 
-  const RealFourier* rf_;
+  T rf_;
   const RealFourier::fft_real_scoper real_buffer_;
   const RealFourier::fft_cplx_scoper cplx_buffer_;
 };
 
-TEST_F(RealFourierTest, SimpleForwardTransform) {
-  real_buffer_[0] = 1.0f;
-  real_buffer_[1] = 2.0f;
-  real_buffer_[2] = 3.0f;
-  real_buffer_[3] = 4.0f;
+using FftTypes = ::testing::Types<
+#if defined(RTC_USE_OPENMAX_DL)
+    RealFourierOpenmax,
+#endif
+    RealFourierOoura>;
+TYPED_TEST_CASE(RealFourierTest, FftTypes);
 
-  rf_->Forward(real_buffer_.get(), cplx_buffer_.get());
+TYPED_TEST(RealFourierTest, SimpleForwardTransform) {
+  this->real_buffer_[0] = 1.0f;
+  this->real_buffer_[1] = 2.0f;
+  this->real_buffer_[2] = 3.0f;
+  this->real_buffer_[3] = 4.0f;
 
-  ASSERT_NEAR(cplx_buffer_[0].real(), 10.0f, 1e-8f);
-  ASSERT_NEAR(cplx_buffer_[0].imag(), 0.0f, 1e-8f);
-  ASSERT_NEAR(cplx_buffer_[1].real(), -2.0f, 1e-8f);
-  ASSERT_NEAR(cplx_buffer_[1].imag(), 2.0f, 1e-8f);
-  ASSERT_NEAR(cplx_buffer_[2].real(), -2.0f, 1e-8f);
-  ASSERT_NEAR(cplx_buffer_[2].imag(), 0.0f, 1e-8f);
+  this->rf_.Forward(this->real_buffer_.get(), this->cplx_buffer_.get());
+
+  EXPECT_NEAR(this->cplx_buffer_[0].real(), 10.0f, 1e-8f);
+  EXPECT_NEAR(this->cplx_buffer_[0].imag(), 0.0f, 1e-8f);
+  EXPECT_NEAR(this->cplx_buffer_[1].real(), -2.0f, 1e-8f);
+  EXPECT_NEAR(this->cplx_buffer_[1].imag(), 2.0f, 1e-8f);
+  EXPECT_NEAR(this->cplx_buffer_[2].real(), -2.0f, 1e-8f);
+  EXPECT_NEAR(this->cplx_buffer_[2].imag(), 0.0f, 1e-8f);
 }
 
-TEST_F(RealFourierTest, SimpleBackwardTransform) {
-  cplx_buffer_[0] = complex<float>(10.0f, 0.0f);
-  cplx_buffer_[1] = complex<float>(-2.0f, 2.0f);
-  cplx_buffer_[2] = complex<float>(-2.0f, 0.0f);
+TYPED_TEST(RealFourierTest, SimpleBackwardTransform) {
+  this->cplx_buffer_[0] = complex<float>(10.0f, 0.0f);
+  this->cplx_buffer_[1] = complex<float>(-2.0f, 2.0f);
+  this->cplx_buffer_[2] = complex<float>(-2.0f, 0.0f);
 
-  rf_->Inverse(cplx_buffer_.get(), real_buffer_.get());
+  this->rf_.Inverse(this->cplx_buffer_.get(), this->real_buffer_.get());
 
-  ASSERT_NEAR(real_buffer_[0], 1.0f, 1e-8f);
-  ASSERT_NEAR(real_buffer_[1], 2.0f, 1e-8f);
-  ASSERT_NEAR(real_buffer_[2], 3.0f, 1e-8f);
-  ASSERT_NEAR(real_buffer_[3], 4.0f, 1e-8f);
+  EXPECT_NEAR(this->real_buffer_[0], 1.0f, 1e-8f);
+  EXPECT_NEAR(this->real_buffer_[1], 2.0f, 1e-8f);
+  EXPECT_NEAR(this->real_buffer_[2], 3.0f, 1e-8f);
+  EXPECT_NEAR(this->real_buffer_[3], 4.0f, 1e-8f);
 }
 
 }  // namespace webrtc
diff --git a/webrtc/modules/audio_processing/BUILD.gn b/webrtc/modules/audio_processing/BUILD.gn
index b34c41c..e4ee782 100644
--- a/webrtc/modules/audio_processing/BUILD.gn
+++ b/webrtc/modules/audio_processing/BUILD.gn
@@ -116,8 +116,6 @@
     "utility/delay_estimator_internal.h",
     "utility/delay_estimator_wrapper.c",
     "utility/delay_estimator_wrapper.h",
-    "utility/fft4g.c",
-    "utility/fft4g.h",
     "voice_detection_impl.cc",
     "voice_detection_impl.h",
   ]
diff --git a/webrtc/modules/audio_processing/agc/agc_audio_proc.cc b/webrtc/modules/audio_processing/agc/agc_audio_proc.cc
index ccc77cc..dc4a5a7 100644
--- a/webrtc/modules/audio_processing/agc/agc_audio_proc.cc
+++ b/webrtc/modules/audio_processing/agc/agc_audio_proc.cc
@@ -13,6 +13,7 @@
 #include <math.h>
 #include <stdio.h>
 
+#include "webrtc/common_audio/fft4g.h"
 #include "webrtc/modules/audio_processing/agc/agc_audio_proc_internal.h"
 #include "webrtc/modules/audio_processing/agc/pitch_internal.h"
 #include "webrtc/modules/audio_processing/agc/pole_zero_filter.h"
@@ -21,7 +22,6 @@
 #include "webrtc/modules/audio_coding/codecs/isac/main/source/lpc_analysis.h"
 #include "webrtc/modules/audio_coding/codecs/isac/main/source/pitch_estimator.h"
 #include "webrtc/modules/audio_coding/codecs/isac/main/source/structs.h"
-#include "webrtc/modules/audio_processing/utility/fft4g.h"
 }
 #include "webrtc/modules/interface/module_common_types.h"
 
diff --git a/webrtc/modules/audio_processing/audio_processing.gypi b/webrtc/modules/audio_processing/audio_processing.gypi
index 3175cc6..9d1ac8c 100644
--- a/webrtc/modules/audio_processing/audio_processing.gypi
+++ b/webrtc/modules/audio_processing/audio_processing.gypi
@@ -126,8 +126,6 @@
         'utility/delay_estimator_internal.h',
         'utility/delay_estimator_wrapper.c',
         'utility/delay_estimator_wrapper.h',
-        'utility/fft4g.c',
-        'utility/fft4g.h',
         'voice_detection_impl.cc',
         'voice_detection_impl.h',
       ],
diff --git a/webrtc/modules/audio_processing/ns/ns_core.c b/webrtc/modules/audio_processing/ns/ns_core.c
index 56f2f46..9e230dd 100644
--- a/webrtc/modules/audio_processing/ns/ns_core.c
+++ b/webrtc/modules/audio_processing/ns/ns_core.c
@@ -13,11 +13,11 @@
 #include <string.h>
 #include <stdlib.h>
 
+#include "webrtc/common_audio/fft4g.h"
 #include "webrtc/common_audio/signal_processing/include/signal_processing_library.h"
 #include "webrtc/modules/audio_processing/ns/include/noise_suppression.h"
 #include "webrtc/modules/audio_processing/ns/ns_core.h"
 #include "webrtc/modules/audio_processing/ns/windows_private.h"
-#include "webrtc/modules/audio_processing/utility/fft4g.h"
 
 // Set Feature Extraction Parameters.
 static void set_feature_extraction_parameters(NoiseSuppressionC* self) {
diff --git a/webrtc/modules/audio_processing/transient/transient_suppressor.cc b/webrtc/modules/audio_processing/transient/transient_suppressor.cc
index 44ea6bf..2f79a20 100644
--- a/webrtc/modules/audio_processing/transient/transient_suppressor.cc
+++ b/webrtc/modules/audio_processing/transient/transient_suppressor.cc
@@ -18,14 +18,12 @@
 #include <set>
 
 #include "webrtc/base/scoped_ptr.h"
+#include "webrtc/common_audio/fft4g.h"
 #include "webrtc/common_audio/include/audio_util.h"
 #include "webrtc/common_audio/signal_processing/include/signal_processing_library.h"
 #include "webrtc/modules/audio_processing/transient/common.h"
 #include "webrtc/modules/audio_processing/transient/transient_detector.h"
 #include "webrtc/modules/audio_processing/ns/windows_private.h"
-extern "C" {
-#include "webrtc/modules/audio_processing/utility/fft4g.h"
-}
 #include "webrtc/system_wrappers/interface/logging.h"
 #include "webrtc/typedefs.h"
 
@@ -39,10 +37,12 @@
 static const size_t kMaxVoiceBin = 60;
 
 namespace {
+
 float ComplexMagnitude(float a, float b) {
   return std::abs(a) + std::abs(b);
 }
-}
+
+}  // namespace
 
 TransientSuppressor::TransientSuppressor()
     : data_length_(0),
diff --git a/webrtc/modules/audio_processing/utility/fft4g.h b/webrtc/modules/audio_processing/utility/fft4g.h
deleted file mode 100644
index 14a52a1..0000000
--- a/webrtc/modules/audio_processing/utility/fft4g.h
+++ /dev/null
@@ -1,17 +0,0 @@
-/*
- *  Copyright (c) 2011 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_PROCESSING_UTILITY_FFT4G_H_
-#define WEBRTC_MODULES_AUDIO_PROCESSING_UTILITY_FFT4G_H_
-
-void WebRtc_rdft(int, int, float *, int *, float *);
-void WebRtc_cdft(int, int, float *, int *, float *);
-
-#endif