Remove non-functional asynchronous resampling mode.

A few other cleanups, most notably using a sane parameter to specify the
number of channels.

BUG=chromium:469814
R=tina.legrand@webrtc.org

Review URL: https://webrtc-codereview.appspot.com/46729004

Cr-Commit-Position: refs/heads/master@{#8894}
This commit is contained in:
Andrew MacDonald 2015-03-30 10:08:22 -07:00
parent 45c6449114
commit 2c9c83d7ec
8 changed files with 96 additions and 265 deletions

View File

@ -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_;

View File

@ -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<ResamplerType>(
((static_cast<int>(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

View File

@ -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

View File

@ -25,8 +25,7 @@ bool ResampleInputAudioFile::Read(size_t samples,
rtc::scoped_ptr<int16_t[]> 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<int>(samples_to_read),

View File

@ -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)

View File

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

View File

@ -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.";

View File

@ -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);
}