Add API to swap stereo channels.

BUG=issue451
TEST=manually with voe_cmd_test, using stereo and mono codecs

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

git-svn-id: http://webrtc.googlecode.com/svn/trunk@2106 4adac7df-926f-26a2-2b94-8c16560cd09d
diff --git a/src/voice_engine/main/interface/voe_audio_processing.h b/src/voice_engine/main/interface/voe_audio_processing.h
index 525f4d4..f75df89 100644
--- a/src/voice_engine/main/interface/voe_audio_processing.h
+++ b/src/voice_engine/main/interface/voe_audio_processing.h
@@ -206,6 +206,16 @@
                                              int reportingThreshold,
                                              int penaltyDecay) = 0;
 
+    // Swaps the capture-side left and right audio channels when enabled. It
+    // only has an effect when using a stereo send codec. The setting is
+    // persistent; it will be applied whenever a stereo send codec is enabled.
+    //
+    // The swap is applied only to the captured audio, and not mixed files. The
+    // swap will appear in file recordings and when accessing audio through the
+    // external media interface.
+    virtual void EnableStereoChannelSwapping(bool enable) = 0;
+    virtual bool IsStereoChannelSwappingEnabled() = 0;
+
 protected:
     VoEAudioProcessing() {}
     virtual ~VoEAudioProcessing() {}
diff --git a/src/voice_engine/main/source/audio_frame_operations.cc b/src/voice_engine/main/source/audio_frame_operations.cc
index e08d0a2..2ff8068 100644
--- a/src/voice_engine/main/source/audio_frame_operations.cc
+++ b/src/voice_engine/main/source/audio_frame_operations.cc
@@ -1,5 +1,5 @@
 /*
- *  Copyright (c) 2011 The WebRTC project authors. All Rights Reserved.
+ *  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
@@ -15,7 +15,7 @@
 
 namespace voe {
 
-WebRtc_Word32 
+WebRtc_Word32
 AudioFrameOperations::MonoToStereo(AudioFrame& audioFrame)
 {
     if (audioFrame._audioChannel != 1)
@@ -29,10 +29,9 @@
         return -1;
     }
 
-    WebRtc_Word16* payloadCopy =
-        new WebRtc_Word16[audioFrame._payloadDataLengthInSamples];
+    int16_t payloadCopy[AudioFrame::kMaxAudioFrameSizeSamples];
     memcpy(payloadCopy, audioFrame._payloadData,
-           sizeof(WebRtc_Word16)*audioFrame._payloadDataLengthInSamples);
+           sizeof(int16_t) * audioFrame._payloadDataLengthInSamples);
 
     for (int i = 0; i < audioFrame._payloadDataLengthInSamples; i++)
     {
@@ -42,11 +41,10 @@
 
     audioFrame._audioChannel = 2;
 
-    delete [] payloadCopy;
     return 0;
 }
 
-WebRtc_Word32 
+WebRtc_Word32
 AudioFrameOperations::StereoToMono(AudioFrame& audioFrame)
 {
     if (audioFrame._audioChannel != 2)
@@ -65,7 +63,15 @@
     return 0;
 }
 
-WebRtc_Word32 
+void AudioFrameOperations::SwapStereoChannels(AudioFrame* frame) {
+  for (int i = 0; i < frame->_payloadDataLengthInSamples * 2; i += 2) {
+    int16_t temp_data = frame->_payloadData[i];
+    frame->_payloadData[i] = frame->_payloadData[i + 1];
+    frame->_payloadData[i + 1] = temp_data;
+  }
+}
+
+WebRtc_Word32
 AudioFrameOperations::Mute(AudioFrame& audioFrame)
 {
     const int sizeInBytes = sizeof(WebRtc_Word16) *
@@ -75,7 +81,7 @@
     return 0;
 }
 
-WebRtc_Word32 
+WebRtc_Word32
 AudioFrameOperations::Scale(const float left,
                             const float right,
                             AudioFrame& audioFrame)
@@ -96,7 +102,7 @@
     return 0;
 }
 
-WebRtc_Word32 
+WebRtc_Word32
 AudioFrameOperations::ScaleWithSat(const float scale, AudioFrame& audioFrame)
 {
     WebRtc_Word32 tmp(0);
diff --git a/src/voice_engine/main/source/audio_frame_operations.h b/src/voice_engine/main/source/audio_frame_operations.h
index 368850b..ec09d44 100644
--- a/src/voice_engine/main/source/audio_frame_operations.h
+++ b/src/voice_engine/main/source/audio_frame_operations.h
@@ -1,5 +1,5 @@
 /*
- *  Copyright (c) 2011 The WebRTC project authors. All Rights Reserved.
+ *  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
@@ -26,6 +26,10 @@
 
     static WebRtc_Word32 StereoToMono(AudioFrame& audioFrame);
 
+    // Swap the left and right channels of |frame|. Fails silently if |frame|
+    // is not stereo.
+    static void SwapStereoChannels(AudioFrame* frame);
+
     static WebRtc_Word32 Mute(AudioFrame& audioFrame);
 
     static WebRtc_Word32 Scale(const float left,
diff --git a/src/voice_engine/main/source/transmit_mixer.cc b/src/voice_engine/main/source/transmit_mixer.cc
index ecceb8b..de14246 100644
--- a/src/voice_engine/main/source/transmit_mixer.cc
+++ b/src/voice_engine/main/source/transmit_mixer.cc
@@ -201,12 +201,13 @@
     _mute(false),
     _remainingMuteMicTimeMs(0),
     _mixingFrequency(0),
-    _includeAudioLevelIndication(false)
+    _includeAudioLevelIndication(false),
+    swap_stereo_channels_(false)
 {
     WEBRTC_TRACE(kTraceMemory, kTraceVoice, VoEId(_instanceId, -1),
                  "TransmitMixer::TransmitMixer() - ctor");
 }
-	
+
 TransmitMixer::~TransmitMixer()
 {
     WEBRTC_TRACE(kTraceMemory, kTraceVoice, VoEId(_instanceId, -1),
@@ -324,19 +325,18 @@
     void* iterator(NULL);
     Channel* channelPtr = sc.GetFirstChannel(iterator);
     _mixingFrequency = 8000;
-    while (channelPtr != NULL)
-    {
-        if (channelPtr->Sending())
-        {
-            CodecInst tmpCdc;
-            channelPtr->GetSendCodec(tmpCdc);
-            if (tmpCdc.plfreq > _mixingFrequency)
-                _mixingFrequency = tmpCdc.plfreq;
-        }
-        channelPtr = sc.GetNextChannel(iterator);
+    bool stereo_codec = false;  // Used for stereo swapping.
+    while (channelPtr != NULL) {
+      if (channelPtr->Sending()) {
+        CodecInst temp_codec;
+        channelPtr->GetSendCodec(temp_codec);
+        stereo_codec = temp_codec.channels == 2;
+        if (temp_codec.plfreq > _mixingFrequency)
+          _mixingFrequency = temp_codec.plfreq;
+      }
+      channelPtr = sc.GetNextChannel(iterator);
     }
 
-
     // --- Resample input audio and create/store the initial audio frame
 
     if (GenerateAudioFrame((const WebRtc_Word16*) audioSamples,
@@ -352,6 +352,10 @@
 
     APMProcessStream(totalDelayMS, clockDrift, currentMicLevel);
 
+    if (swap_stereo_channels_ && stereo_codec)
+      // Only bother swapping if we're using a stereo codec.
+      AudioFrameOperations::SwapStereoChannels(&_audioFrame);
+
     // --- Annoying typing detection (utilizes the APM/VAD decision)
 
 #ifdef WEBRTC_VOICE_ENGINE_TYPING_DETECTION
@@ -1465,6 +1469,14 @@
 }
 #endif
 
+void TransmitMixer::EnableStereoChannelSwapping(bool enable) {
+  swap_stereo_channels_ = enable;
+}
+
+bool TransmitMixer::IsStereoChannelSwappingEnabled() {
+  return swap_stereo_channels_;
+}
+
 }  //  namespace voe
 
 }  //  namespace webrtc
diff --git a/src/voice_engine/main/source/transmit_mixer.h b/src/voice_engine/main/source/transmit_mixer.h
index 77697c1..c74115c 100644
--- a/src/voice_engine/main/source/transmit_mixer.h
+++ b/src/voice_engine/main/source/transmit_mixer.h
@@ -133,11 +133,11 @@
 
     virtual ~TransmitMixer();
 
-public:	// MonitorObserver
+    // MonitorObserver
     void OnPeriodicProcess();
 
 
-public: // FileCallback
+    // FileCallback
     void PlayNotification(const WebRtc_Word32 id,
                           const WebRtc_UWord32 durationMs);
 
@@ -149,7 +149,7 @@
     void RecordFileEnded(const WebRtc_Word32 id);
 
 #ifdef WEBRTC_VOICE_ENGINE_TYPING_DETECTION
-public:  // Typing detection
+    // Typing detection
     int TimeSinceLastTyping(int &seconds);
     int SetTypingDetectionParameters(int timeWindow,
                                      int costPerTyping,
@@ -157,10 +157,12 @@
                                      int penaltyDecay);
 #endif
 
+  void EnableStereoChannelSwapping(bool enable);
+  bool IsStereoChannelSwappingEnabled();
+
 private:
     TransmitMixer(const WebRtc_UWord32 instanceId);
 
-private:
     WebRtc_Word32 GenerateAudioFrame(const WebRtc_Word16 audioSamples[],
                                      const WebRtc_UWord32 nSamples,
                                      const WebRtc_UWord8 nChannels,
@@ -179,14 +181,14 @@
     int TypingDetection();
 #endif
 
-private:  // uses
+    // uses
     Statistics* _engineStatisticsPtr;
     ChannelManager* _channelManagerPtr;
     AudioProcessing* _audioProcessingModulePtr;
     VoiceEngineObserver* _voiceEngineObserverPtr;
     ProcessThread* _processThreadPtr;
 
-private:  // owns
+    // owns
     MonitorModule _monitorModule;
     AudioFrame _audioFrame;
     Resampler _audioResampler;		// ADM sample rate -> mixing rate
@@ -220,7 +222,6 @@
     WebRtc_UWord32 _saturationWarning;
     WebRtc_UWord32 _noiseWarning;
 
-private:
     int _instanceId;
     bool _mixFileWithMicrophone;
     WebRtc_UWord32 _captureLevel;
@@ -230,6 +231,7 @@
     WebRtc_Word32 _remainingMuteMicTimeMs;
     int _mixingFrequency;
     bool _includeAudioLevelIndication;
+    bool swap_stereo_channels_;
 };
 
 #endif // WEBRTC_VOICE_ENGINE_TRANSMIT_MIXER_H
diff --git a/src/voice_engine/main/source/voe_audio_processing_impl.cc b/src/voice_engine/main/source/voe_audio_processing_impl.cc
index 501c0c6..8f518d0 100644
--- a/src/voice_engine/main/source/voe_audio_processing_impl.cc
+++ b/src/voice_engine/main/source/voe_audio_processing_impl.cc
@@ -18,6 +18,13 @@
 #include "voe_errors.h"
 #include "voice_engine_impl.h"
 
+// TODO(andrew): move to a common place.
+#define WEBRTC_TRACE_VOICE_API()                                   \
+  do {                                                             \
+    WEBRTC_TRACE(kTraceApiCall, kTraceVoice,                       \
+                 VoEId(_shared->instance_id(), -1), __FUNCTION__); \
+  } while (0)
+
 namespace webrtc {
 
 #if defined(WEBRTC_ANDROID) || defined(MAC_IPHONE) || defined(MAC_IPHONE_SIM)
@@ -1108,6 +1115,17 @@
 
 }
 
+void VoEAudioProcessingImpl::EnableStereoChannelSwapping(bool enable) {
+  WEBRTC_TRACE(kTraceApiCall, kTraceVoice, VoEId(_shared->instance_id(), -1),
+               "EnableStereoChannelSwapping(enable=%d)", enable);
+  _shared->transmit_mixer()->EnableStereoChannelSwapping(enable);
+}
+
+bool VoEAudioProcessingImpl::IsStereoChannelSwappingEnabled() {
+  WEBRTC_TRACE_VOICE_API();
+  return _shared->transmit_mixer()->IsStereoChannelSwappingEnabled();
+}
+
 
 
 #endif  // #ifdef WEBRTC_VOICE_ENGINE_AUDIO_PROCESSING_API
diff --git a/src/voice_engine/main/source/voe_audio_processing_impl.h b/src/voice_engine/main/source/voe_audio_processing_impl.h
index 1c75f13..11c4ef5 100644
--- a/src/voice_engine/main/source/voe_audio_processing_impl.h
+++ b/src/voice_engine/main/source/voe_audio_processing_impl.h
@@ -98,6 +98,9 @@
                                            int reportingThreshold,
                                            int penaltyDecay);
 
+  virtual void EnableStereoChannelSwapping(bool enable);
+  virtual bool IsStereoChannelSwappingEnabled();
+
  protected:
   VoEAudioProcessingImpl(voe::SharedData* shared);
   virtual ~VoEAudioProcessingImpl();