Add external media hook for preprocessed audio.

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

git-svn-id: http://webrtc.googlecode.com/svn/trunk/src@2960 4adac7df-926f-26a2-2b94-8c16560cd09d
diff --git a/common_types.h b/common_types.h
index 0d71f3f..83c55a3 100644
--- a/common_types.h
+++ b/common_types.h
@@ -131,7 +131,8 @@
     kPlaybackPerChannel = 0,
     kPlaybackAllChannelsMixed,
     kRecordingPerChannel,
-    kRecordingAllChannelsMixed
+    kRecordingAllChannelsMixed,
+    kRecordingPreprocessing
 };
 
 // Encryption enums
diff --git a/voice_engine/transmit_mixer.cc b/voice_engine/transmit_mixer.cc
index d987c4e..452af1c 100644
--- a/voice_engine/transmit_mixer.cc
+++ b/voice_engine/transmit_mixer.cc
@@ -202,8 +202,8 @@
     _instanceId(instanceId),
     _mixFileWithMicrophone(false),
     _captureLevel(0),
-    _externalMedia(false),
-    _externalMediaCallbackPtr(NULL),
+    external_postproc_ptr_(NULL),
+    external_preproc_ptr_(NULL),
     _mute(false),
     _remainingMuteMicTimeMs(0),
     _mixingFrequency(0),
@@ -223,10 +223,8 @@
     {
         _processThreadPtr->DeRegisterModule(&_monitorModule);
     }
-    if (_externalMedia)
-    {
-        DeRegisterExternalMediaProcessing();
-    }
+    DeRegisterExternalMediaProcessing(kRecordingAllChannelsMixed);
+    DeRegisterExternalMediaProcessing(kRecordingPreprocessing);
     {
         CriticalSectionScoped cs(&_critSect);
         if (_fileRecorderPtr)
@@ -362,6 +360,17 @@
         return -1;
     }
 
+    {
+      CriticalSectionScoped cs(&_callbackCritSect);
+      if (external_preproc_ptr_) {
+        external_preproc_ptr_->Process(-1, kRecordingPreprocessing,
+                                       _audioFrame.data_,
+                                       _audioFrame.samples_per_channel_,
+                                       _audioFrame.sample_rate_hz_,
+                                       _audioFrame.num_channels_ == 2);
+      }
+    }
+
     // --- Near-end Voice Quality Enhancement (APM) processing
 
     APMProcessStream(totalDelayMS, clockDrift, currentMicLevel);
@@ -413,22 +422,15 @@
         RecordAudioToFile(_mixingFrequency);
     }
 
-    // --- External media processing
-
-    if (_externalMedia)
     {
-        CriticalSectionScoped cs(&_callbackCritSect);
-        const bool isStereo = (_audioFrame.num_channels_ == 2);
-        if (_externalMediaCallbackPtr)
-        {
-            _externalMediaCallbackPtr->Process(
-                -1,
-                kRecordingAllChannelsMixed,
-                (WebRtc_Word16*) _audioFrame.data_,
-                _audioFrame.samples_per_channel_,
-                _audioFrame.sample_rate_hz_,
-                isStereo);
-        }
+      CriticalSectionScoped cs(&_callbackCritSect);
+      if (external_postproc_ptr_) {
+        external_postproc_ptr_->Process(-1, kRecordingAllChannelsMixed,
+                                        _audioFrame.data_,
+                                        _audioFrame.samples_per_channel_,
+                                        _audioFrame.sample_rate_hz_,
+                                        _audioFrame.num_channels_ == 2);
+      }
     }
 
     return 0;
@@ -1095,28 +1097,40 @@
 }
 
 int TransmitMixer::RegisterExternalMediaProcessing(
-    VoEMediaProcess& proccess_object)
-{
-    WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId, -1),
-                 "TransmitMixer::RegisterExternalMediaProcessing()");
+    VoEMediaProcess* object,
+    ProcessingTypes type) {
+  WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId, -1),
+               "TransmitMixer::RegisterExternalMediaProcessing()");
 
-    CriticalSectionScoped cs(&_callbackCritSect);
-    _externalMediaCallbackPtr = &proccess_object;
-    _externalMedia = true;
+  CriticalSectionScoped cs(&_callbackCritSect);
+  if (!object) {
+    return -1;
+  }
 
-    return 0;
+  // Store the callback object according to the processing type.
+  if (type == kRecordingAllChannelsMixed) {
+    external_postproc_ptr_ = object;
+  } else if (type == kRecordingPreprocessing) {
+    external_preproc_ptr_ = object;
+  } else {
+    return -1;
+  }
+  return 0;
 }
 
-int TransmitMixer::DeRegisterExternalMediaProcessing()
-{
-    WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId, -1),
-                 "TransmitMixer::DeRegisterExternalMediaProcessing()");
+int TransmitMixer::DeRegisterExternalMediaProcessing(ProcessingTypes type) {
+  WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId, -1),
+               "TransmitMixer::DeRegisterExternalMediaProcessing()");
 
-    CriticalSectionScoped cs(&_callbackCritSect);
-    _externalMedia = false;
-    _externalMediaCallbackPtr = NULL;
-
-    return 0;
+  CriticalSectionScoped cs(&_callbackCritSect);
+  if (type == kRecordingAllChannelsMixed) {
+    external_postproc_ptr_ = NULL;
+  } else if (type == kRecordingPreprocessing) {
+    external_preproc_ptr_ = NULL;
+  } else {
+    return -1;
+  }
+  return 0;
 }
 
 int
diff --git a/voice_engine/transmit_mixer.h b/voice_engine/transmit_mixer.h
index da87218..0dac049 100644
--- a/voice_engine/transmit_mixer.h
+++ b/voice_engine/transmit_mixer.h
@@ -73,9 +73,9 @@
     void UpdateMuteMicrophoneTime(const WebRtc_UWord32 lengthMs);
 
     // VoEExternalMedia
-    int RegisterExternalMediaProcessing(VoEMediaProcess& proccess_object);
-
-    int DeRegisterExternalMediaProcessing();
+    int RegisterExternalMediaProcessing(VoEMediaProcess* object,
+                                        ProcessingTypes type);
+    int DeRegisterExternalMediaProcessing(ProcessingTypes type);
 
     int GetMixingFrequency();
 
@@ -193,8 +193,8 @@
     // owns
     MonitorModule _monitorModule;
     AudioFrame _audioFrame;
-    Resampler _audioResampler;		// ADM sample rate -> mixing rate
-    FilePlayer*	_filePlayerPtr;
+    Resampler _audioResampler; // ADM sample rate -> mixing rate
+    FilePlayer* _filePlayerPtr;
     FileRecorder* _fileRecorderPtr;
     FileRecorder* _fileCallRecorderPtr;
     int _filePlayerId;
@@ -228,8 +228,8 @@
     int _instanceId;
     bool _mixFileWithMicrophone;
     WebRtc_UWord32 _captureLevel;
-    bool _externalMedia;
-    VoEMediaProcess* _externalMediaCallbackPtr;
+    VoEMediaProcess* external_postproc_ptr_;
+    VoEMediaProcess* external_preproc_ptr_;
     bool _mute;
     WebRtc_Word32 _remainingMuteMicTimeMs;
     int _mixingFrequency;
diff --git a/voice_engine/transmit_mixer_unittest.cc b/voice_engine/transmit_mixer_unittest.cc
new file mode 100644
index 0000000..d8d85b6
--- /dev/null
+++ b/voice_engine/transmit_mixer_unittest.cc
@@ -0,0 +1,59 @@
+/*
+ *  Copyright (c) 2012 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 "voice_engine/transmit_mixer.h"
+
+#include "gtest/gtest.h"
+#include "voice_engine/include/voe_external_media.h"
+
+namespace webrtc {
+namespace voe {
+namespace {
+
+class MediaCallback : public VoEMediaProcess {
+ public:
+  virtual void Process(const int channel, const ProcessingTypes type,
+                       int16_t audio[], const int samples_per_channel,
+                       const int sample_rate_hz, const bool is_stereo) {
+  }
+};
+
+// TODO(andrew): Mock VoEMediaProcess, and verify the behavior when calling
+// PrepareDemux().
+TEST(TransmitMixerTest, RegisterExternalMediaCallback) {
+  TransmitMixer* tm = NULL;
+  ASSERT_EQ(0, TransmitMixer::Create(tm, 0));
+  ASSERT_TRUE(tm != NULL);
+  MediaCallback callback;
+  EXPECT_EQ(-1, tm->RegisterExternalMediaProcessing(NULL,
+                                                    kRecordingPreprocessing));
+  EXPECT_EQ(-1, tm->RegisterExternalMediaProcessing(&callback,
+                                                    kPlaybackPerChannel));
+  EXPECT_EQ(-1, tm->RegisterExternalMediaProcessing(&callback,
+                                                    kPlaybackAllChannelsMixed));
+  EXPECT_EQ(-1, tm->RegisterExternalMediaProcessing(&callback,
+                                                    kRecordingPerChannel));
+  EXPECT_EQ(0, tm->RegisterExternalMediaProcessing(&callback,
+                                                   kRecordingAllChannelsMixed));
+  EXPECT_EQ(0, tm->RegisterExternalMediaProcessing(&callback,
+                                                   kRecordingPreprocessing));
+  EXPECT_EQ(-1, tm->DeRegisterExternalMediaProcessing(kPlaybackPerChannel));
+  EXPECT_EQ(-1, tm->DeRegisterExternalMediaProcessing(
+                    kPlaybackAllChannelsMixed));
+  EXPECT_EQ(-1, tm->DeRegisterExternalMediaProcessing(kRecordingPerChannel));
+  EXPECT_EQ(0, tm->DeRegisterExternalMediaProcessing(
+                   kRecordingAllChannelsMixed));
+  EXPECT_EQ(0, tm->DeRegisterExternalMediaProcessing(kRecordingPreprocessing));
+  TransmitMixer::Destroy(tm);
+}
+
+}  // namespace
+}  // namespace voe
+}  // namespace webrtc
diff --git a/voice_engine/voe_external_media_impl.cc b/voice_engine/voe_external_media_impl.cc
index 0158c3d..0216023 100644
--- a/voice_engine/voe_external_media_impl.cc
+++ b/voice_engine/voe_external_media_impl.cc
@@ -88,9 +88,10 @@
                 processObject);
         }
         case kRecordingAllChannelsMixed:
+        case kRecordingPreprocessing:
         {
             return shared_->transmit_mixer()->RegisterExternalMediaProcessing(
-                processObject);
+                &processObject, type);
         }
     }
     return -1;
@@ -131,9 +132,10 @@
                 DeRegisterExternalMediaProcessing();
         }
         case kRecordingAllChannelsMixed:
+        case kRecordingPreprocessing:
         {
             return shared_->transmit_mixer()->
-                DeRegisterExternalMediaProcessing();
+                DeRegisterExternalMediaProcessing(type);
         }
     }
     return -1;
diff --git a/voice_engine/voice_engine_core.gypi b/voice_engine/voice_engine_core.gypi
index 79d55cd..0478a71 100644
--- a/voice_engine/voice_engine_core.gypi
+++ b/voice_engine/voice_engine_core.gypi
@@ -144,6 +144,7 @@
           'sources': [
             'channel_unittest.cc',
             'output_mixer_unittest.cc',
+            'transmit_mixer_unittest.cc',
             'voe_audio_processing_unittest.cc',
           ],
         },