diff --git a/src/voice_engine/main/interface/voe_audio_processing.h b/src/voice_engine/main/interface/voe_audio_processing.h index 525f4d44ea..f75df898ce 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 @@ public: 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 e08d0a2740..2ff80680e7 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 webrtc { namespace voe { -WebRtc_Word32 +WebRtc_Word32 AudioFrameOperations::MonoToStereo(AudioFrame& audioFrame) { if (audioFrame._audioChannel != 1) @@ -29,10 +29,9 @@ AudioFrameOperations::MonoToStereo(AudioFrame& audioFrame) 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 @@ AudioFrameOperations::MonoToStereo(AudioFrame& audioFrame) audioFrame._audioChannel = 2; - delete [] payloadCopy; return 0; } -WebRtc_Word32 +WebRtc_Word32 AudioFrameOperations::StereoToMono(AudioFrame& audioFrame) { if (audioFrame._audioChannel != 2) @@ -65,7 +63,15 @@ AudioFrameOperations::StereoToMono(AudioFrame& audioFrame) 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 @@ AudioFrameOperations::Mute(AudioFrame& audioFrame) return 0; } -WebRtc_Word32 +WebRtc_Word32 AudioFrameOperations::Scale(const float left, const float right, AudioFrame& audioFrame) @@ -96,7 +102,7 @@ AudioFrameOperations::Scale(const float left, 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 368850b417..ec09d44f6b 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 @@ public: 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 ecceb8b47b..de1424616f 100644 --- a/src/voice_engine/main/source/transmit_mixer.cc +++ b/src/voice_engine/main/source/transmit_mixer.cc @@ -201,12 +201,13 @@ TransmitMixer::TransmitMixer(const WebRtc_UWord32 instanceId) : _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 @@ TransmitMixer::PrepareDemux(const void* audioSamples, 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 @@ TransmitMixer::PrepareDemux(const void* audioSamples, 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 @@ int TransmitMixer::SetTypingDetectionParameters(int timeWindow, } #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 77697c11d4..c74115c0b4 100644 --- a/src/voice_engine/main/source/transmit_mixer.h +++ b/src/voice_engine/main/source/transmit_mixer.h @@ -133,11 +133,11 @@ public: virtual ~TransmitMixer(); -public: // MonitorObserver + // MonitorObserver void OnPeriodicProcess(); -public: // FileCallback + // FileCallback void PlayNotification(const WebRtc_Word32 id, const WebRtc_UWord32 durationMs); @@ -149,7 +149,7 @@ public: // FileCallback 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 @@ public: // Typing detection 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 @@ private: 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 @@ private: // owns WebRtc_UWord32 _saturationWarning; WebRtc_UWord32 _noiseWarning; -private: int _instanceId; bool _mixFileWithMicrophone; WebRtc_UWord32 _captureLevel; @@ -230,6 +231,7 @@ private: 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 501c0c6e33..8f518d0190 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 @@ int VoEAudioProcessingImpl::SetTypingDetectionParameters(int timeWindow, } +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 1c75f138b5..11c4ef5d78 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 @@ class VoEAudioProcessingImpl int reportingThreshold, int penaltyDecay); + virtual void EnableStereoChannelSwapping(bool enable); + virtual bool IsStereoChannelSwappingEnabled(); + protected: VoEAudioProcessingImpl(voe::SharedData* shared); virtual ~VoEAudioProcessingImpl();