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();