Add multi-mic support for the noise suppression pre-processing effect

Change-Id: I7cf8d5657a25206e0a07e7e343635f7cf23e6f89
diff --git a/media/libeffects/preprocessing/PreProcessing.cpp b/media/libeffects/preprocessing/PreProcessing.cpp
index f3c038b..0a3298e 100644
--- a/media/libeffects/preprocessing/PreProcessing.cpp
+++ b/media/libeffects/preprocessing/PreProcessing.cpp
@@ -89,6 +89,7 @@
     preproc_session_t *session;     // session the effect is on
     const preproc_ops_t *ops;       // effect ops table
     preproc_fx_handle_t engine;     // handle on webRTC engine
+    uint32_t type;                  // subtype of effect
 #ifdef DUAL_MIC_TEST
     bool aux_channels_on;           // support auxiliary channels
     size_t cur_channel_config;      // current auciliary channel configuration
@@ -559,6 +560,21 @@
     ALOGV("NsInit");
     webrtc::NoiseSuppression *ns = static_cast<webrtc::NoiseSuppression *>(effect->engine);
     ns->set_level(kNsDefaultLevel);
+    webrtc::Config config;
+    std::vector<webrtc::Point> geometry;
+    // TODO(aluebs): Make the geometry settable.
+    geometry.push_back(webrtc::Point(-0.03f, 0.f, 0.f));
+    geometry.push_back(webrtc::Point(-0.01f, 0.f, 0.f));
+    geometry.push_back(webrtc::Point(0.01f, 0.f, 0.f));
+    geometry.push_back(webrtc::Point(0.03f, 0.f, 0.f));
+    // The geometry needs to be set with Beamforming enabled.
+    config.Set<webrtc::Beamforming>(
+            new webrtc::Beamforming(true, geometry));
+    effect->session->apm->SetExtraOptions(config);
+    config.Set<webrtc::Beamforming>(
+            new webrtc::Beamforming(false, geometry));
+    effect->session->apm->SetExtraOptions(config);
+    effect->type = NS_TYPE_SINGLE_CHANNEL;
     return 0;
 }
 
@@ -584,11 +600,35 @@
     return status;
 }
 
-int NsSetParameter (preproc_effect_t *effect __unused,
-                    void *pParam __unused,
-                    void *pValue __unused)
+int NsSetParameter (preproc_effect_t *effect, void *pParam, void *pValue)
 {
     int status = 0;
+    webrtc::NoiseSuppression *ns = static_cast<webrtc::NoiseSuppression *>(effect->engine);
+    uint32_t param = *(uint32_t *)pParam;
+    uint32_t value = *(uint32_t *)pValue;
+    switch(param) {
+        case NS_PARAM_LEVEL:
+            ns->set_level((webrtc::NoiseSuppression::Level)value);
+            ALOGV("NsSetParameter() level %d", value);
+            break;
+        case NS_PARAM_TYPE:
+        {
+            webrtc::Config config;
+            std::vector<webrtc::Point> geometry;
+            bool is_beamforming_enabled =
+                    value == NS_TYPE_MULTI_CHANNEL && ns->is_enabled();
+            config.Set<webrtc::Beamforming>(
+                    new webrtc::Beamforming(is_beamforming_enabled, geometry));
+            effect->session->apm->SetExtraOptions(config);
+            effect->type = value;
+            ALOGV("NsSetParameter() type %d", value);
+            break;
+        }
+        default:
+            ALOGW("NsSetParameter() unknown param %08x value %08x", param, value);
+            status = -EINVAL;
+    }
+
     return status;
 }
 
@@ -597,6 +637,12 @@
     webrtc::NoiseSuppression *ns = static_cast<webrtc::NoiseSuppression *>(effect->engine);
     ALOGV("NsEnable ns %p", ns);
     ns->Enable(true);
+    if (effect->type == NS_TYPE_MULTI_CHANNEL) {
+        webrtc::Config config;
+        std::vector<webrtc::Point> geometry;
+        config.Set<webrtc::Beamforming>(new webrtc::Beamforming(true, geometry));
+        effect->session->apm->SetExtraOptions(config);
+    }
 }
 
 void NsDisable(preproc_effect_t *effect)
@@ -604,6 +650,10 @@
     ALOGV("NsDisable");
     webrtc::NoiseSuppression *ns = static_cast<webrtc::NoiseSuppression *>(effect->engine);
     ns->Enable(false);
+    webrtc::Config config;
+    std::vector<webrtc::Point> geometry;
+    config.Set<webrtc::Beamforming>(new webrtc::Beamforming(false, geometry));
+    effect->session->apm->SetExtraOptions(config);
 }
 
 static const preproc_ops_t sNsOps = {
@@ -897,17 +947,6 @@
          config->inputCfg.samplingRate, config->inputCfg.channels);
     int status;
 
-    // if at least one process is enabled, do not accept configuration changes
-    if (session->enabledMsk) {
-        if (session->samplingRate != config->inputCfg.samplingRate ||
-                session->inChannelCount != inCnl ||
-                session->outChannelCount != outCnl) {
-            return -ENOSYS;
-        } else {
-            return 0;
-        }
-    }
-
     // AEC implementation is limited to 16kHz
     if (config->inputCfg.samplingRate >= 32000 && !(session->createdMsk & (1 << PREPROC_AEC))) {
         session->apmSamplingRate = 32000;
@@ -1290,8 +1329,7 @@
             }
             session->framesIn = 0;
         }
-        session->procFrame->samples_per_channel_ =
-                session->apmFrameCount * session->inChannelCount;
+        session->procFrame->samples_per_channel_ = session->apmFrameCount;
 
         effect->session->apm->ProcessStream(session->procFrame);
 
@@ -1802,8 +1840,7 @@
             }
             session->framesRev = 0;
         }
-        session->revFrame->samples_per_channel_ =
-                session->apmFrameCount * session->inChannelCount;
+        session->revFrame->samples_per_channel_ = session->apmFrameCount;
         effect->session->apm->AnalyzeReverseStream(session->revFrame);
         return 0;
     } else {