From f5a33f145b74d9c6058c670baf7b6201b78f6e48 Mon Sep 17 00:00:00 2001 From: "andrew@webrtc.org" Date: Sat, 19 Apr 2014 00:32:07 +0000 Subject: [PATCH] Resampler modifications in preparation for arbitrary audioproc rates. - Templatize PushResampler to support int16 and float. - Add a helper method to PushSincResampler to compute the algorithmic delay. This is a prerequisite of: http://review.webrtc.org/9919004/ BUG=2894 R=turaj@webrtc.org Review URL: https://webrtc-codereview.appspot.com/12169004 git-svn-id: http://webrtc.googlecode.com/svn/trunk@5943 4adac7df-926f-26a2-2b94-8c16560cd09d --- .../resampler/include/push_resampler.h | 15 +++---- .../common_audio/resampler/push_resampler.cc | 40 ++++++++++--------- .../resampler/push_resampler_unittest.cc | 2 +- .../resampler/push_sinc_resampler.h | 3 ++ .../audio_coding/main/acm2/acm_resampler.h | 2 +- .../audio_coding/main/source/acm_resampler.h | 4 +- webrtc/voice_engine/channel.h | 4 +- webrtc/voice_engine/output_mixer.h | 6 ++- webrtc/voice_engine/transmit_mixer.h | 2 +- webrtc/voice_engine/utility.cc | 4 +- webrtc/voice_engine/utility.h | 6 +-- webrtc/voice_engine/utility_unittest.cc | 12 +++--- 12 files changed, 52 insertions(+), 48 deletions(-) diff --git a/webrtc/common_audio/resampler/include/push_resampler.h b/webrtc/common_audio/resampler/include/push_resampler.h index 770a992618..f04dc0f3e8 100644 --- a/webrtc/common_audio/resampler/include/push_resampler.h +++ b/webrtc/common_audio/resampler/include/push_resampler.h @@ -20,6 +20,7 @@ class PushSincResampler; // Wraps PushSincResampler to provide stereo support. // TODO(ajm): add support for an arbitrary number of channels. +template class PushResampler { public: PushResampler(); @@ -32,22 +33,18 @@ class PushResampler { // Returns the total number of samples provided in destination (e.g. 32 kHz, // 2 channel audio gives 640 samples). - int Resample(const int16_t* src, int src_length, int16_t* dst, - int dst_capacity); + int Resample(const T* src, int src_length, T* dst, int dst_capacity); private: - int ResampleSinc(const int16_t* src, int src_length, int16_t* dst, - int dst_capacity); - scoped_ptr sinc_resampler_; scoped_ptr sinc_resampler_right_; int src_sample_rate_hz_; int dst_sample_rate_hz_; int num_channels_; - scoped_array src_left_; - scoped_array src_right_; - scoped_array dst_left_; - scoped_array dst_right_; + scoped_ptr src_left_; + scoped_ptr src_right_; + scoped_ptr dst_left_; + scoped_ptr dst_right_; }; } // namespace webrtc diff --git a/webrtc/common_audio/resampler/push_resampler.cc b/webrtc/common_audio/resampler/push_resampler.cc index 29944187d8..973c8f74f7 100644 --- a/webrtc/common_audio/resampler/push_resampler.cc +++ b/webrtc/common_audio/resampler/push_resampler.cc @@ -18,22 +18,21 @@ namespace webrtc { -PushResampler::PushResampler() +template +PushResampler::PushResampler() : src_sample_rate_hz_(0), dst_sample_rate_hz_(0), - num_channels_(0), - src_left_(NULL), - src_right_(NULL), - dst_left_(NULL), - dst_right_(NULL) { + num_channels_(0) { } -PushResampler::~PushResampler() { +template +PushResampler::~PushResampler() { } -int PushResampler::InitializeIfNeeded(int src_sample_rate_hz, - int dst_sample_rate_hz, - int num_channels) { +template +int PushResampler::InitializeIfNeeded(int src_sample_rate_hz, + int dst_sample_rate_hz, + int num_channels) { if (src_sample_rate_hz == src_sample_rate_hz_ && dst_sample_rate_hz == dst_sample_rate_hz_ && num_channels == num_channels_) @@ -53,10 +52,10 @@ int PushResampler::InitializeIfNeeded(int src_sample_rate_hz, sinc_resampler_.reset(new PushSincResampler(src_size_10ms_mono, dst_size_10ms_mono)); if (num_channels_ == 2) { - src_left_.reset(new int16_t[src_size_10ms_mono]); - src_right_.reset(new int16_t[src_size_10ms_mono]); - dst_left_.reset(new int16_t[dst_size_10ms_mono]); - dst_right_.reset(new int16_t[dst_size_10ms_mono]); + src_left_.reset(new T[src_size_10ms_mono]); + src_right_.reset(new T[src_size_10ms_mono]); + dst_left_.reset(new T[dst_size_10ms_mono]); + dst_right_.reset(new T[dst_size_10ms_mono]); sinc_resampler_right_.reset(new PushSincResampler(src_size_10ms_mono, dst_size_10ms_mono)); } @@ -64,8 +63,9 @@ int PushResampler::InitializeIfNeeded(int src_sample_rate_hz, return 0; } -int PushResampler::Resample(const int16_t* src, int src_length, - int16_t* dst, int dst_capacity) { +template +int PushResampler::Resample(const T* src, int src_length, T* dst, + int dst_capacity) { const int src_size_10ms = src_sample_rate_hz_ * num_channels_ / 100; const int dst_size_10ms = dst_sample_rate_hz_ * num_channels_ / 100; if (src_length != src_size_10ms || dst_capacity < dst_size_10ms) @@ -74,13 +74,13 @@ int PushResampler::Resample(const int16_t* src, int src_length, if (src_sample_rate_hz_ == dst_sample_rate_hz_) { // The old resampler provides this memcpy facility in the case of matching // sample rates, so reproduce it here for the sinc resampler. - memcpy(dst, src, src_length * sizeof(int16_t)); + memcpy(dst, src, src_length * sizeof(T)); return src_length; } if (num_channels_ == 2) { const int src_length_mono = src_length / num_channels_; const int dst_capacity_mono = dst_capacity / num_channels_; - int16_t* deinterleaved[] = {src_left_.get(), src_right_.get()}; + T* deinterleaved[] = {src_left_.get(), src_right_.get()}; Deinterleave(src, src_length_mono, num_channels_, deinterleaved); int dst_length_mono = @@ -98,4 +98,8 @@ int PushResampler::Resample(const int16_t* src, int src_length, } } +// Explictly generate required instantiations. +template class PushResampler; +template class PushResampler; + } // namespace webrtc diff --git a/webrtc/common_audio/resampler/push_resampler_unittest.cc b/webrtc/common_audio/resampler/push_resampler_unittest.cc index c40923bf98..4449f4c633 100644 --- a/webrtc/common_audio/resampler/push_resampler_unittest.cc +++ b/webrtc/common_audio/resampler/push_resampler_unittest.cc @@ -16,7 +16,7 @@ namespace webrtc { TEST(PushResamplerTest, VerifiesInputParameters) { - PushResampler resampler; + PushResampler resampler; EXPECT_EQ(-1, resampler.InitializeIfNeeded(-1, 16000, 1)); EXPECT_EQ(-1, resampler.InitializeIfNeeded(16000, -1, 1)); EXPECT_EQ(-1, resampler.InitializeIfNeeded(16000, 16000, 0)); diff --git a/webrtc/common_audio/resampler/push_sinc_resampler.h b/webrtc/common_audio/resampler/push_sinc_resampler.h index fa1bb3e71d..7c804fea9c 100644 --- a/webrtc/common_audio/resampler/push_sinc_resampler.h +++ b/webrtc/common_audio/resampler/push_sinc_resampler.h @@ -44,6 +44,9 @@ class PushSincResampler : public SincResamplerCallback { virtual void Run(int frames, float* destination) OVERRIDE; SincResampler* get_resampler_for_testing() { return resampler_.get(); } + static float AlgorithmicDelaySeconds(int source_rate_hz) { + return 1.f / source_rate_hz * SincResampler::kKernelSize / 2; + } private: scoped_ptr resampler_; diff --git a/webrtc/modules/audio_coding/main/acm2/acm_resampler.h b/webrtc/modules/audio_coding/main/acm2/acm_resampler.h index 5d952e54b8..644a32f05b 100644 --- a/webrtc/modules/audio_coding/main/acm2/acm_resampler.h +++ b/webrtc/modules/audio_coding/main/acm2/acm_resampler.h @@ -29,7 +29,7 @@ class ACMResampler { int16_t* out_audio); private: - PushResampler resampler_; + PushResampler resampler_; }; } // namespace acm2 diff --git a/webrtc/modules/audio_coding/main/source/acm_resampler.h b/webrtc/modules/audio_coding/main/source/acm_resampler.h index b50e722c44..ceeae05f22 100644 --- a/webrtc/modules/audio_coding/main/source/acm_resampler.h +++ b/webrtc/modules/audio_coding/main/source/acm_resampler.h @@ -15,7 +15,6 @@ #include "webrtc/typedefs.h" namespace webrtc { - namespace acm1 { class ACMResampler { @@ -30,11 +29,10 @@ class ACMResampler { uint8_t num_audio_channels); private: - PushResampler resampler_; + PushResampler resampler_; }; } // namespace acm1 - } // namespace webrtc #endif // WEBRTC_MODULES_AUDIO_CODING_MAIN_SOURCE_ACM_RESAMPLER_H_ diff --git a/webrtc/voice_engine/channel.h b/webrtc/voice_engine/channel.h index 3377be0ee4..8f47b48c63 100644 --- a/webrtc/voice_engine/channel.h +++ b/webrtc/voice_engine/channel.h @@ -519,8 +519,8 @@ private: bool _externalTransport; AudioFrame _audioFrame; scoped_ptr mono_recording_audio_; - // Resampler is used when input data is stereo while codec is mono. - PushResampler input_resampler_; + // Downsamples to the codec rate if necessary. + PushResampler input_resampler_; uint8_t _audioLevel_dBov; FilePlayer* _inputFilePlayerPtr; FilePlayer* _outputFilePlayerPtr; diff --git a/webrtc/voice_engine/output_mixer.h b/webrtc/voice_engine/output_mixer.h index bd17c3beca..859ce64bdd 100644 --- a/webrtc/voice_engine/output_mixer.h +++ b/webrtc/voice_engine/output_mixer.h @@ -133,8 +133,10 @@ private: CriticalSectionWrapper& _fileCritSect; AudioConferenceMixer& _mixerModule; AudioFrame _audioFrame; - PushResampler resampler_; // converts mixed audio to fit ADM format - PushResampler audioproc_resampler_; // converts mixed audio to fit APM rate + // Converts mixed audio to the audio device output rate. + PushResampler resampler_; + // Converts mixed audio to the audio processing rate. + PushResampler audioproc_resampler_; AudioLevel _audioLevel; // measures audio level for the combined signal DtmfInband _dtmfGenerator; int _instanceId; diff --git a/webrtc/voice_engine/transmit_mixer.h b/webrtc/voice_engine/transmit_mixer.h index b408614ae9..cc61130888 100644 --- a/webrtc/voice_engine/transmit_mixer.h +++ b/webrtc/voice_engine/transmit_mixer.h @@ -200,7 +200,7 @@ private: // owns MonitorModule _monitorModule; AudioFrame _audioFrame; - PushResampler resampler_; // ADM sample rate -> mixing rate + PushResampler resampler_; // ADM sample rate -> mixing rate FilePlayer* _filePlayerPtr; FileRecorder* _fileRecorderPtr; FileRecorder* _fileCallRecorderPtr; diff --git a/webrtc/voice_engine/utility.cc b/webrtc/voice_engine/utility.cc index 5058aa3213..b7eb885c5a 100644 --- a/webrtc/voice_engine/utility.cc +++ b/webrtc/voice_engine/utility.cc @@ -25,7 +25,7 @@ namespace voe { // ConvertToCodecFormat, but if we're to consolidate we should probably make a // real converter class. void RemixAndResample(const AudioFrame& src_frame, - PushResampler* resampler, + PushResampler* resampler, AudioFrame* dst_frame) { const int16_t* audio_ptr = src_frame.data_; int audio_ptr_num_channels = src_frame.num_channels_; @@ -76,7 +76,7 @@ void DownConvertToCodecFormat(const int16_t* src_data, int codec_num_channels, int codec_rate_hz, int16_t* mono_buffer, - PushResampler* resampler, + PushResampler* resampler, AudioFrame* dst_af) { assert(samples_per_channel <= kMaxMonoDataSizeSamples); assert(num_channels == 1 || num_channels == 2); diff --git a/webrtc/voice_engine/utility.h b/webrtc/voice_engine/utility.h index f6fa35bf73..127bdba066 100644 --- a/webrtc/voice_engine/utility.h +++ b/webrtc/voice_engine/utility.h @@ -15,12 +15,12 @@ #ifndef WEBRTC_VOICE_ENGINE_UTILITY_H_ #define WEBRTC_VOICE_ENGINE_UTILITY_H_ +#include "webrtc/common_audio/resampler/include/push_resampler.h" #include "webrtc/typedefs.h" namespace webrtc { class AudioFrame; -class PushResampler; namespace voe { @@ -30,7 +30,7 @@ namespace voe { // // On failure, returns -1 and copies |src_frame| to |dst_frame|. void RemixAndResample(const AudioFrame& src_frame, - PushResampler* resampler, + PushResampler* resampler, AudioFrame* dst_frame); // Downmix and downsample the audio in |src_data| to |dst_af| as necessary, @@ -44,7 +44,7 @@ void DownConvertToCodecFormat(const int16_t* src_data, int codec_num_channels, int codec_rate_hz, int16_t* mono_buffer, - PushResampler* resampler, + PushResampler* resampler, AudioFrame* dst_af); void MixWithSat(int16_t target[], diff --git a/webrtc/voice_engine/utility_unittest.cc b/webrtc/voice_engine/utility_unittest.cc index a5d0bcd821..8f7efa87f6 100644 --- a/webrtc/voice_engine/utility_unittest.cc +++ b/webrtc/voice_engine/utility_unittest.cc @@ -39,7 +39,7 @@ class UtilityTest : public ::testing::Test { int dst_channels, int dst_sample_rate_hz, FunctionToTest function); - PushResampler resampler_; + PushResampler resampler_; AudioFrame src_frame_; AudioFrame dst_frame_; AudioFrame golden_frame_; @@ -127,11 +127,11 @@ void VerifyFramesAreEqual(const AudioFrame& ref_frame, } void UtilityTest::RunResampleTest(int src_channels, - int src_sample_rate_hz, - int dst_channels, - int dst_sample_rate_hz, - FunctionToTest function) { - PushResampler resampler; // Create a new one with every test. + int src_sample_rate_hz, + int dst_channels, + int dst_sample_rate_hz, + FunctionToTest function) { + PushResampler resampler; // Create a new one with every test. const int16_t kSrcLeft = 30; // Shouldn't overflow for any used sample rate. const int16_t kSrcRight = 15; const float resampling_factor = (1.0 * src_sample_rate_hz) /