diff --git a/src/common_types.h b/src/common_types.h index 0d71f3fb3..83c55a3c0 100644 --- a/src/common_types.h +++ b/src/common_types.h @@ -131,7 +131,8 @@ enum ProcessingTypes kPlaybackPerChannel = 0, kPlaybackAllChannelsMixed, kRecordingPerChannel, - kRecordingAllChannelsMixed + kRecordingAllChannelsMixed, + kRecordingPreprocessing }; // Encryption enums diff --git a/src/voice_engine/transmit_mixer.cc b/src/voice_engine/transmit_mixer.cc index d987c4e9c..452af1cff 100644 --- a/src/voice_engine/transmit_mixer.cc +++ b/src/voice_engine/transmit_mixer.cc @@ -202,8 +202,8 @@ TransmitMixer::TransmitMixer(const WebRtc_UWord32 instanceId) : _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 @@ TransmitMixer::~TransmitMixer() { _processThreadPtr->DeRegisterModule(&_monitorModule); } - if (_externalMedia) - { - DeRegisterExternalMediaProcessing(); - } + DeRegisterExternalMediaProcessing(kRecordingAllChannelsMixed); + DeRegisterExternalMediaProcessing(kRecordingPreprocessing); { CriticalSectionScoped cs(&_critSect); if (_fileRecorderPtr) @@ -362,6 +360,17 @@ TransmitMixer::PrepareDemux(const void* audioSamples, 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 @@ TransmitMixer::PrepareDemux(const void* audioSamples, 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 @@ TransmitMixer::SetMixWithMicStatus(bool mix) } 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/src/voice_engine/transmit_mixer.h b/src/voice_engine/transmit_mixer.h index da87218cd..0dac04993 100644 --- a/src/voice_engine/transmit_mixer.h +++ b/src/voice_engine/transmit_mixer.h @@ -73,9 +73,9 @@ public: 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 @@ private: // 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 @@ private: 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/src/voice_engine/transmit_mixer_unittest.cc b/src/voice_engine/transmit_mixer_unittest.cc new file mode 100644 index 000000000..d8d85b62b --- /dev/null +++ b/src/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/src/voice_engine/voe_external_media_impl.cc b/src/voice_engine/voe_external_media_impl.cc index 0158c3d97..021602380 100644 --- a/src/voice_engine/voe_external_media_impl.cc +++ b/src/voice_engine/voe_external_media_impl.cc @@ -88,9 +88,10 @@ int VoEExternalMediaImpl::RegisterExternalMediaProcessing( processObject); } case kRecordingAllChannelsMixed: + case kRecordingPreprocessing: { return shared_->transmit_mixer()->RegisterExternalMediaProcessing( - processObject); + &processObject, type); } } return -1; @@ -131,9 +132,10 @@ int VoEExternalMediaImpl::DeRegisterExternalMediaProcessing( DeRegisterExternalMediaProcessing(); } case kRecordingAllChannelsMixed: + case kRecordingPreprocessing: { return shared_->transmit_mixer()-> - DeRegisterExternalMediaProcessing(); + DeRegisterExternalMediaProcessing(type); } } return -1; diff --git a/src/voice_engine/voice_engine_core.gypi b/src/voice_engine/voice_engine_core.gypi index 79d55cd0a..0478a710d 100644 --- a/src/voice_engine/voice_engine_core.gypi +++ b/src/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', ], },