diff --git a/webrtc/common_audio/resampler/include/resampler.h b/webrtc/common_audio/resampler/include/resampler.h index 08c24730f..4b63e9c10 100644 --- a/webrtc/common_audio/resampler/include/resampler.h +++ b/webrtc/common_audio/resampler/include/resampler.h @@ -18,48 +18,7 @@ #include "webrtc/typedefs.h" -namespace webrtc -{ - -// TODO(andrew): the implementation depends on the exact values of this enum. -// It should be rewritten in a less fragile way. -enum ResamplerType -{ - // 4 MSB = Number of channels - // 4 LSB = Synchronous or asynchronous - - kResamplerSynchronous = 0x10, - kResamplerAsynchronous = 0x11, - kResamplerSynchronousStereo = 0x20, - kResamplerAsynchronousStereo = 0x21, - kResamplerInvalid = 0xff -}; - -// TODO(andrew): doesn't need to be part of the interface. -enum ResamplerMode -{ - kResamplerMode1To1, - kResamplerMode1To2, - kResamplerMode1To3, - kResamplerMode1To4, - kResamplerMode1To6, - kResamplerMode1To12, - kResamplerMode2To3, - kResamplerMode2To11, - kResamplerMode4To11, - kResamplerMode8To11, - kResamplerMode11To16, - kResamplerMode11To32, - kResamplerMode2To1, - kResamplerMode3To1, - kResamplerMode4To1, - kResamplerMode6To1, - kResamplerMode12To1, - kResamplerMode3To2, - kResamplerMode11To2, - kResamplerMode11To4, - kResamplerMode11To8 -}; +namespace webrtc { // All methods return 0 on success and -1 on failure. class Resampler @@ -67,26 +26,45 @@ class Resampler public: Resampler(); - Resampler(int inFreq, int outFreq, ResamplerType type); + Resampler(int inFreq, int outFreq, int num_channels); ~Resampler(); // Reset all states - int Reset(int inFreq, int outFreq, ResamplerType type); + int Reset(int inFreq, int outFreq, int num_channels); // Reset all states if any parameter has changed - int ResetIfNeeded(int inFreq, int outFreq, ResamplerType type); + int ResetIfNeeded(int inFreq, int outFreq, int num_channels); - // Synchronous resampling, all output samples are written to samplesOut + // Resample samplesIn to samplesOut. int Push(const int16_t* samplesIn, int lengthIn, int16_t* samplesOut, int maxLen, int &outLen); - // Asynchronous resampling, input - int Insert(int16_t* samplesIn, int lengthIn); - - // Asynchronous resampling output, remaining samples are buffered - int Pull(int16_t* samplesOut, int desiredLen, int &outLen); - private: + enum ResamplerMode + { + kResamplerMode1To1, + kResamplerMode1To2, + kResamplerMode1To3, + kResamplerMode1To4, + kResamplerMode1To6, + kResamplerMode1To12, + kResamplerMode2To3, + kResamplerMode2To11, + kResamplerMode4To11, + kResamplerMode8To11, + kResamplerMode11To16, + kResamplerMode11To32, + kResamplerMode2To1, + kResamplerMode3To1, + kResamplerMode4To1, + kResamplerMode6To1, + kResamplerMode12To1, + kResamplerMode3To2, + kResamplerMode11To2, + kResamplerMode11To4, + kResamplerMode11To8 + }; + // Generic pointers since we don't know what states we'll need void* state1_; void* state2_; @@ -100,11 +78,10 @@ private: int in_buffer_size_max_; int out_buffer_size_max_; - // State int my_in_frequency_khz_; int my_out_frequency_khz_; ResamplerMode my_mode_; - ResamplerType my_type_; + int num_channels_; // Extra instance for stereo Resampler* slave_left_; diff --git a/webrtc/common_audio/resampler/resampler.cc b/webrtc/common_audio/resampler/resampler.cc index 071e551d8..f65742e27 100644 --- a/webrtc/common_audio/resampler/resampler.cc +++ b/webrtc/common_audio/resampler/resampler.cc @@ -19,50 +19,29 @@ #include "webrtc/common_audio/resampler/include/resampler.h" #include "webrtc/common_audio/signal_processing/include/signal_processing_library.h" - -namespace webrtc -{ +namespace webrtc { Resampler::Resampler() -{ - state1_ = NULL; - state2_ = NULL; - state3_ = NULL; - in_buffer_ = NULL; - out_buffer_ = NULL; - in_buffer_size_ = 0; - out_buffer_size_ = 0; - in_buffer_size_max_ = 0; - out_buffer_size_max_ = 0; - // we need a reset before we will work - my_in_frequency_khz_ = 0; - my_out_frequency_khz_ = 0; - my_mode_ = kResamplerMode1To1; - my_type_ = kResamplerInvalid; - slave_left_ = NULL; - slave_right_ = NULL; + : state1_(nullptr), + state2_(nullptr), + state3_(nullptr), + in_buffer_(nullptr), + out_buffer_(nullptr), + in_buffer_size_(0), + out_buffer_size_(0), + in_buffer_size_max_(0), + out_buffer_size_max_(0), + my_in_frequency_khz_(0), + my_out_frequency_khz_(0), + my_mode_(kResamplerMode1To1), + num_channels_(0), + slave_left_(nullptr), + slave_right_(nullptr) { } -Resampler::Resampler(int inFreq, int outFreq, ResamplerType type) -{ - state1_ = NULL; - state2_ = NULL; - state3_ = NULL; - in_buffer_ = NULL; - out_buffer_ = NULL; - in_buffer_size_ = 0; - out_buffer_size_ = 0; - in_buffer_size_max_ = 0; - out_buffer_size_max_ = 0; - // we need a reset before we will work - my_in_frequency_khz_ = 0; - my_out_frequency_khz_ = 0; - my_mode_ = kResamplerMode1To1; - my_type_ = kResamplerInvalid; - slave_left_ = NULL; - slave_right_ = NULL; - - Reset(inFreq, outFreq, type); +Resampler::Resampler(int inFreq, int outFreq, int num_channels) + : Resampler() { + Reset(inFreq, outFreq, num_channels); } Resampler::~Resampler() @@ -97,23 +76,27 @@ Resampler::~Resampler() } } -int Resampler::ResetIfNeeded(int inFreq, int outFreq, ResamplerType type) +int Resampler::ResetIfNeeded(int inFreq, int outFreq, int num_channels) { int tmpInFreq_kHz = inFreq / 1000; int tmpOutFreq_kHz = outFreq / 1000; if ((tmpInFreq_kHz != my_in_frequency_khz_) || (tmpOutFreq_kHz != my_out_frequency_khz_) - || (type != my_type_)) + || (num_channels != num_channels_)) { - return Reset(inFreq, outFreq, type); + return Reset(inFreq, outFreq, num_channels); } else { return 0; } } -int Resampler::Reset(int inFreq, int outFreq, ResamplerType type) +int Resampler::Reset(int inFreq, int outFreq, int num_channels) { + if (num_channels != 1 && num_channels != 2) { + return -1; + } + num_channels_ = num_channels; if (state1_) { @@ -156,11 +139,7 @@ int Resampler::Reset(int inFreq, int outFreq, ResamplerType type) in_buffer_size_max_ = 0; out_buffer_size_max_ = 0; - // This might be overridden if parameters are not accepted. - my_type_ = type; - // Start with a math exercise, Euclid's algorithm to find the gcd: - int a = inFreq; int b = outFreq; int c = a % b; @@ -180,14 +159,11 @@ int Resampler::Reset(int inFreq, int outFreq, ResamplerType type) inFreq = inFreq / b; outFreq = outFreq / b; - // Do we need stereo? - if ((my_type_ & 0xf0) == 0x20) + if (num_channels_ == 2) { - // Change type to mono - type = static_cast( - ((static_cast(type) & 0x0f) + 0x10)); - slave_left_ = new Resampler(inFreq, outFreq, type); - slave_right_ = new Resampler(inFreq, outFreq, type); + // Create two mono resamplers. + slave_left_ = new Resampler(inFreq, outFreq, 1); + slave_right_ = new Resampler(inFreq, outFreq, 1); } if (inFreq == outFreq) @@ -213,7 +189,6 @@ int Resampler::Reset(int inFreq, int outFreq, ResamplerType type) my_mode_ = kResamplerMode1To12; break; default: - my_type_ = kResamplerInvalid; return -1; } } else if (outFreq == 1) @@ -236,7 +211,6 @@ int Resampler::Reset(int inFreq, int outFreq, ResamplerType type) my_mode_ = kResamplerMode12To1; break; default: - my_type_ = kResamplerInvalid; return -1; } } else if ((inFreq == 2) && (outFreq == 3)) @@ -271,7 +245,6 @@ int Resampler::Reset(int inFreq, int outFreq, ResamplerType type) my_mode_ = kResamplerMode11To8; } else { - my_type_ = kResamplerInvalid; return -1; } @@ -428,21 +401,12 @@ int Resampler::Reset(int inFreq, int outFreq, ResamplerType type) } // Synchronous resampling, all output samples are written to samplesOut -int Resampler::Push(const int16_t * samplesIn, int lengthIn, int16_t* samplesOut, - int maxLen, int &outLen) +int Resampler::Push(const int16_t * samplesIn, int lengthIn, + int16_t* samplesOut, int maxLen, int &outLen) { - // Check that the resampler is not in asynchronous mode - if (my_type_ & 0x0f) + if (num_channels_ == 2) { - return -1; - } - - // Do we have a stereo signal? - if ((my_type_ & 0xf0) == 0x20) - { - // Split up the signal and call the slave object for each channel - int16_t* left = (int16_t*)malloc(lengthIn * sizeof(int16_t) / 2); int16_t* right = (int16_t*)malloc(lengthIn * sizeof(int16_t) / 2); int16_t* out_left = (int16_t*)malloc(maxLen / 2 * sizeof(int16_t)); @@ -992,93 +956,4 @@ int Resampler::Push(const int16_t * samplesIn, int lengthIn, int16_t* samplesOut return 0; } -// Asynchronous resampling, input -int Resampler::Insert(int16_t * samplesIn, int lengthIn) -{ - if (my_type_ != kResamplerAsynchronous) - { - return -1; - } - int sizeNeeded, tenMsblock; - - // Determine need for size of outBuffer - sizeNeeded = out_buffer_size_ + ((lengthIn + in_buffer_size_) * my_out_frequency_khz_) - / my_in_frequency_khz_; - if (sizeNeeded > out_buffer_size_max_) - { - // Round the value upwards to complete 10 ms blocks - tenMsblock = my_out_frequency_khz_ * 10; - sizeNeeded = (sizeNeeded / tenMsblock + 1) * tenMsblock; - out_buffer_ = (int16_t*)realloc(out_buffer_, sizeNeeded * sizeof(int16_t)); - out_buffer_size_max_ = sizeNeeded; - } - - // If we need to use inBuffer, make sure all input data fits there. - - tenMsblock = my_in_frequency_khz_ * 10; - if (in_buffer_size_ || (lengthIn % tenMsblock)) - { - // Check if input buffer size is enough - if ((in_buffer_size_ + lengthIn) > in_buffer_size_max_) - { - // Round the value upwards to complete 10 ms blocks - sizeNeeded = ((in_buffer_size_ + lengthIn) / tenMsblock + 1) * tenMsblock; - in_buffer_ = (int16_t*)realloc(in_buffer_, - sizeNeeded * sizeof(int16_t)); - in_buffer_size_max_ = sizeNeeded; - } - // Copy in data to input buffer - memcpy(in_buffer_ + in_buffer_size_, samplesIn, lengthIn * sizeof(int16_t)); - - // Resample all available 10 ms blocks - int lenOut; - int dataLenToResample = (in_buffer_size_ / tenMsblock) * tenMsblock; - Push(in_buffer_, dataLenToResample, out_buffer_ + out_buffer_size_, - out_buffer_size_max_ - out_buffer_size_, lenOut); - out_buffer_size_ += lenOut; - - // Save the rest - memmove(in_buffer_, in_buffer_ + dataLenToResample, - (in_buffer_size_ - dataLenToResample) * sizeof(int16_t)); - in_buffer_size_ -= dataLenToResample; - } else - { - // Just resample - int lenOut; - Push(in_buffer_, lengthIn, out_buffer_ + out_buffer_size_, - out_buffer_size_max_ - out_buffer_size_, lenOut); - out_buffer_size_ += lenOut; - } - - return 0; -} - -// Asynchronous resampling output, remaining samples are buffered -int Resampler::Pull(int16_t* samplesOut, int desiredLen, int &outLen) -{ - if (my_type_ != kResamplerAsynchronous) - { - return -1; - } - - // Check that we have enough data - if (desiredLen <= out_buffer_size_) - { - // Give out the date - memcpy(samplesOut, out_buffer_, desiredLen * sizeof(int32_t)); - - // Shuffle down remaining - memmove(out_buffer_, out_buffer_ + desiredLen, - (out_buffer_size_ - desiredLen) * sizeof(int16_t)); - - // Update remaining size - out_buffer_size_ -= desiredLen; - - return 0; - } else - { - return -1; - } -} - } // namespace webrtc diff --git a/webrtc/common_audio/resampler/resampler_unittest.cc b/webrtc/common_audio/resampler/resampler_unittest.cc index 3d1091d41..40a31bb0e 100644 --- a/webrtc/common_audio/resampler/resampler_unittest.cc +++ b/webrtc/common_audio/resampler/resampler_unittest.cc @@ -16,14 +16,9 @@ namespace webrtc { namespace { -const ResamplerType kTypes[] = { - kResamplerSynchronous, - kResamplerAsynchronous, - kResamplerSynchronousStereo, - kResamplerAsynchronousStereo - // kResamplerInvalid excluded -}; -const size_t kTypesSize = sizeof(kTypes) / sizeof(*kTypes); + +const int kNumChannels[] = {1, 2}; +const size_t kNumChannelsSize = sizeof(kNumChannels) / sizeof(*kNumChannels); // Rates we must support. const int kMaxRate = 96000; @@ -78,15 +73,15 @@ TEST_F(ResamplerTest, Reset) { // Check that all required combinations are supported. for (size_t i = 0; i < kRatesSize; ++i) { for (size_t j = 0; j < kRatesSize; ++j) { - for (size_t k = 0; k < kTypesSize; ++k) { + for (size_t k = 0; k < kNumChannelsSize; ++k) { std::ostringstream ss; ss << "Input rate: " << kRates[i] << ", output rate: " << kRates[j] - << ", type: " << kTypes[k]; + << ", channels: " << kNumChannels[k]; SCOPED_TRACE(ss.str()); if (ValidRates(kRates[i], kRates[j])) - EXPECT_EQ(0, rs_.Reset(kRates[i], kRates[j], kTypes[k])); + EXPECT_EQ(0, rs_.Reset(kRates[i], kRates[j], kNumChannels[k])); else - EXPECT_EQ(-1, rs_.Reset(kRates[i], kRates[j], kTypes[k])); + EXPECT_EQ(-1, rs_.Reset(kRates[i], kRates[j], kNumChannels[k])); } } } @@ -94,7 +89,8 @@ TEST_F(ResamplerTest, Reset) { // TODO(tlegrand): Replace code inside the two tests below with a function // with number of channels and ResamplerType as input. -TEST_F(ResamplerTest, Synchronous) { +TEST_F(ResamplerTest, Mono) { + const int kChannels = 1; for (size_t i = 0; i < kRatesSize; ++i) { for (size_t j = 0; j < kRatesSize; ++j) { std::ostringstream ss; @@ -104,19 +100,18 @@ TEST_F(ResamplerTest, Synchronous) { if (ValidRates(kRates[i], kRates[j])) { int in_length = kRates[i] / 100; int out_length = 0; - EXPECT_EQ(0, rs_.Reset(kRates[i], kRates[j], kResamplerSynchronous)); + EXPECT_EQ(0, rs_.Reset(kRates[i], kRates[j], kChannels)); EXPECT_EQ(0, rs_.Push(data_in_, in_length, data_out_, kDataSize, out_length)); EXPECT_EQ(kRates[j] / 100, out_length); } else { - EXPECT_EQ(-1, rs_.Reset(kRates[i], kRates[j], kResamplerSynchronous)); + EXPECT_EQ(-1, rs_.Reset(kRates[i], kRates[j], kChannels)); } } } } -TEST_F(ResamplerTest, SynchronousStereo) { - // Number of channels is 2, stereo mode. +TEST_F(ResamplerTest, Stereo) { const int kChannels = 2; for (size_t i = 0; i < kRatesSize; ++i) { for (size_t j = 0; j < kRatesSize; ++j) { @@ -128,16 +123,17 @@ TEST_F(ResamplerTest, SynchronousStereo) { int in_length = kChannels * kRates[i] / 100; int out_length = 0; EXPECT_EQ(0, rs_.Reset(kRates[i], kRates[j], - kResamplerSynchronousStereo)); + kChannels)); EXPECT_EQ(0, rs_.Push(data_in_, in_length, data_out_, kDataSize, out_length)); EXPECT_EQ(kChannels * kRates[j] / 100, out_length); } else { EXPECT_EQ(-1, rs_.Reset(kRates[i], kRates[j], - kResamplerSynchronousStereo)); + kChannels)); } } } } + } // namespace } // namespace webrtc diff --git a/webrtc/modules/audio_coding/neteq/tools/resample_input_audio_file.cc b/webrtc/modules/audio_coding/neteq/tools/resample_input_audio_file.cc index ea88a3fa5..74d593e6a 100644 --- a/webrtc/modules/audio_coding/neteq/tools/resample_input_audio_file.cc +++ b/webrtc/modules/audio_coding/neteq/tools/resample_input_audio_file.cc @@ -25,8 +25,7 @@ bool ResampleInputAudioFile::Read(size_t samples, rtc::scoped_ptr temp_destination(new int16_t[samples_to_read]); if (!InputAudioFile::Read(samples_to_read, temp_destination.get())) return false; - resampler_.ResetIfNeeded( - file_rate_hz_, output_rate_hz, kResamplerSynchronous); + resampler_.ResetIfNeeded(file_rate_hz_, output_rate_hz, 1); int output_length = 0; CHECK_EQ(resampler_.Push(temp_destination.get(), static_cast(samples_to_read), diff --git a/webrtc/modules/audio_device/test/func_test_manager.cc b/webrtc/modules/audio_device/test/func_test_manager.cc index d6e5cb3d9..abb58c954 100644 --- a/webrtc/modules/audio_device/test/func_test_manager.cc +++ b/webrtc/modules/audio_device/test/func_test_manager.cc @@ -96,7 +96,7 @@ AudioTransportImpl::AudioTransportImpl(AudioDeviceModule* audioDevice) : _recCount(0), _playCount(0) { - _resampler.Reset(48000, 48000, kResamplerSynchronousStereo); + _resampler.Reset(48000, 48000, 2); } AudioTransportImpl::~AudioTransportImpl() @@ -332,8 +332,7 @@ int32_t AudioTransportImpl::NeedMorePlayData( if (nChannelsIn == 2 && nBytesPerSampleIn == 4) { // input is stereo => we will resample in stereo - ret = _resampler.ResetIfNeeded(fsInHz, fsOutHz, - kResamplerSynchronousStereo); + ret = _resampler.ResetIfNeeded(fsInHz, fsOutHz, 2); if (ret == 0) { if (nChannels == 2) @@ -374,8 +373,7 @@ int32_t AudioTransportImpl::NeedMorePlayData( { // input is mono (can be "reduced from stereo" as well) => // we will resample in mono - ret = _resampler.ResetIfNeeded(fsInHz, fsOutHz, - kResamplerSynchronous); + ret = _resampler.ResetIfNeeded(fsInHz, fsOutHz, 1); if (ret == 0) { if (nChannels == 1) diff --git a/webrtc/modules/audio_processing/agc/agc.cc b/webrtc/modules/audio_processing/agc/agc.cc index dda1636d0..6041435bd 100644 --- a/webrtc/modules/audio_processing/agc/agc.cc +++ b/webrtc/modules/audio_processing/agc/agc.cc @@ -45,7 +45,7 @@ Agc::Agc() pitch_based_vad_(new PitchBasedVad()), standalone_vad_(StandaloneVad::Create()), // Initialize to the most common resampling situation. - resampler_(new Resampler(32000, kSampleRateHz, kResamplerSynchronous)) { + resampler_(new Resampler(32000, kSampleRateHz, 1)) { } Agc::~Agc() {} @@ -69,9 +69,7 @@ int Agc::Process(const int16_t* audio, int length, int sample_rate_hz) { int16_t resampled[kLength10Ms]; const int16_t* resampled_ptr = audio; if (sample_rate_hz != kSampleRateHz) { - if (resampler_->ResetIfNeeded(sample_rate_hz, - kSampleRateHz, - kResamplerSynchronous) != 0) { + if (resampler_->ResetIfNeeded(sample_rate_hz, kSampleRateHz, 1) != 0) { return -1; } resampler_->Push(audio, length, resampled, kLength10Ms, length); diff --git a/webrtc/modules/utility/source/file_player_impl.cc b/webrtc/modules/utility/source/file_player_impl.cc index 1803e8adf..df6a5bfbc 100644 --- a/webrtc/modules/utility/source/file_player_impl.cc +++ b/webrtc/modules/utility/source/file_player_impl.cc @@ -130,7 +130,7 @@ int32_t FilePlayerImpl::Get10msAudioFromFile( unresampledAudioFrame.samples_per_channel_ = (uint16_t)lengthInBytes >> 1; - }else { + } else { // Decode will generate 10 ms of audio data. PlayoutAudioData(..) // expects a full frame. If the frame size is larger than 10 ms, // PlayoutAudioData(..) data should be called proportionally less often. @@ -158,7 +158,7 @@ int32_t FilePlayerImpl::Get10msAudioFromFile( int outLen = 0; if(_resampler.ResetIfNeeded(unresampledAudioFrame.sample_rate_hz_, - frequencyInHz, kResamplerSynchronous)) + frequencyInHz, 1)) { LOG(LS_WARNING) << "Get10msAudioFromFile() unexpected codec."; diff --git a/webrtc/modules/utility/source/file_recorder_impl.cc b/webrtc/modules/utility/source/file_recorder_impl.cc index 29eede8c0..0a2c9a088 100644 --- a/webrtc/modules/utility/source/file_recorder_impl.cc +++ b/webrtc/modules/utility/source/file_recorder_impl.cc @@ -211,26 +211,14 @@ int32_t FileRecorderImpl::RecordAudioToFile( } } else { int outLen = 0; - if(ptrAudioFrame->num_channels_ == 2) - { - // ptrAudioFrame contains interleaved stereo audio. - _audioResampler.ResetIfNeeded(ptrAudioFrame->sample_rate_hz_, - codec_info_.plfreq, - kResamplerSynchronousStereo); - _audioResampler.Push(ptrAudioFrame->data_, - ptrAudioFrame->samples_per_channel_ * - ptrAudioFrame->num_channels_, - (int16_t*)_audioBuffer, - MAX_AUDIO_BUFFER_IN_BYTES, outLen); - } else { - _audioResampler.ResetIfNeeded(ptrAudioFrame->sample_rate_hz_, - codec_info_.plfreq, - kResamplerSynchronous); - _audioResampler.Push(ptrAudioFrame->data_, - ptrAudioFrame->samples_per_channel_, - (int16_t*)_audioBuffer, - MAX_AUDIO_BUFFER_IN_BYTES, outLen); - } + _audioResampler.ResetIfNeeded(ptrAudioFrame->sample_rate_hz_, + codec_info_.plfreq, + ptrAudioFrame->num_channels_); + _audioResampler.Push(ptrAudioFrame->data_, + ptrAudioFrame->samples_per_channel_ * + ptrAudioFrame->num_channels_, + (int16_t*)_audioBuffer, + MAX_AUDIO_BUFFER_IN_BYTES, outLen); encodedLenInBytes = outLen * sizeof(int16_t); }