Index: media/base/audio_renderer_mixer_unittest.cc |
diff --git a/media/base/audio_renderer_mixer_unittest.cc b/media/base/audio_renderer_mixer_unittest.cc |
index b218fa0410070d9d2c765f49bff06453eaa48f1f..8d2b5d43a80309f44e24b75ac5a3493ee96c3ea5 100644 |
--- a/media/base/audio_renderer_mixer_unittest.cc |
+++ b/media/base/audio_renderer_mixer_unittest.cc |
@@ -23,6 +23,7 @@ namespace media { |
// Parameters which control the many input case tests. |
const int kMixerInputs = 8; |
+const int kOddMixerInputs = 7; |
const int kMixerCycles = 3; |
// Parameters used for testing. |
@@ -34,22 +35,37 @@ const int kLowLatencyBufferSize = 256; |
// Number of full sine wave cycles for each Render() call. |
const int kSineCycles = 4; |
-// Default device ID |
+// Default device ID. |
const std::string kDefaultDeviceId; |
const url::Origin kDefaultSecurityOrigin; |
-// Tuple of <input sampling rate, output sampling rate, epsilon>. |
-typedef std::tr1::tuple<int, int, double> AudioRendererMixerTestData; |
+// Input sample frequencies for testing. |
+std::vector<int> kTestInputLower(1, 44100); |
+std::vector<int> kTestInputHigher(1, 48000); |
+const int kSampleRates[] = {22050, 44100, 48000}; |
+std::vector<int> kTestInput3Rates(kSampleRates, |
+ kSampleRates + |
+ sizeof(kSampleRates) / |
+ sizeof(kSampleRates[0])); |
+ |
+// Tuple of <input sampling rates, output sampling rate, epsilon>. |
+typedef std::tr1::tuple<std::vector<int>, int, double> |
+ AudioRendererMixerTestData; |
+ |
class AudioRendererMixerTest |
: public testing::TestWithParam<AudioRendererMixerTestData> { |
public: |
AudioRendererMixerTest() |
: epsilon_(std::tr1::get<2>(GetParam())), |
half_fill_(false) { |
- // Create input and output parameters based on test parameters. |
- input_parameters_ = AudioParameters( |
- AudioParameters::AUDIO_PCM_LINEAR, kChannelLayout, |
- std::tr1::get<0>(GetParam()), kBitsPerChannel, kHighLatencyBufferSize); |
+ // Create input parameters based on test parameters. |
+ const std::vector<int>& sample_rates(std::tr1::get<0>(GetParam())); |
+ for (size_t i = 0; i < sample_rates.size(); ++i) |
+ input_parameters_.push_back(AudioParameters( |
+ AudioParameters::AUDIO_PCM_LINEAR, kChannelLayout, sample_rates[i], |
+ kBitsPerChannel, kHighLatencyBufferSize)); |
+ |
+ // Create output parameters based on test parameters. |
output_parameters_ = AudioParameters( |
AudioParameters::AUDIO_PCM_LOW_LATENCY, kChannelLayout, |
std::tr1::get<1>(GetParam()), 16, kLowLatencyBufferSize); |
@@ -58,8 +74,7 @@ class AudioRendererMixerTest |
EXPECT_CALL(*sink_.get(), Start()); |
EXPECT_CALL(*sink_.get(), Stop()); |
- mixer_.reset(new AudioRendererMixer( |
- input_parameters_, output_parameters_, sink_)); |
+ mixer_.reset(new AudioRendererMixer(output_parameters_, sink_)); |
mixer_callback_ = sink_->callback(); |
audio_bus_ = AudioBus::Create(output_parameters_); |
@@ -83,28 +98,35 @@ class AudioRendererMixerTest |
const std::string&, |
const url::Origin&)); |
- void InitializeInputs(int count) { |
- mixer_inputs_.reserve(count); |
- fake_callbacks_.reserve(count); |
- |
- // Setup FakeAudioRenderCallback step to compensate for resampling. |
- double scale_factor = input_parameters_.sample_rate() / |
- static_cast<double>(output_parameters_.sample_rate()); |
- double step = kSineCycles / (scale_factor * |
- static_cast<double>(output_parameters_.frames_per_buffer())); |
- |
- for (int i = 0; i < count; ++i) { |
- fake_callbacks_.push_back(new FakeAudioRenderCallback(step)); |
- mixer_inputs_.push_back(new AudioRendererMixerInput( |
- base::Bind(&AudioRendererMixerTest::GetMixer, base::Unretained(this)), |
- base::Bind(&AudioRendererMixerTest::RemoveMixer, |
- base::Unretained(this)), |
- kDefaultDeviceId, kDefaultSecurityOrigin)); |
- mixer_inputs_[i]->Initialize(input_parameters_, fake_callbacks_[i]); |
- mixer_inputs_[i]->SetVolume(1.0f); |
+ void InitializeInputs(int inputs_per_sample_rate) { |
+ mixer_inputs_.reserve(inputs_per_sample_rate * input_parameters_.size()); |
+ fake_callbacks_.reserve(inputs_per_sample_rate * input_parameters_.size()); |
+ |
+ for (size_t i = 0, input = 0; i < input_parameters_.size(); ++i) { |
+ // Setup FakeAudioRenderCallback step to compensate for resampling. |
+ double scale_factor = |
+ input_parameters_[i].sample_rate() / |
+ static_cast<double>(output_parameters_.sample_rate()); |
+ double step = |
+ kSineCycles / |
+ (scale_factor * |
+ static_cast<double>(output_parameters_.frames_per_buffer())); |
+ |
+ for (int j = 0; j < inputs_per_sample_rate; ++j, ++input) { |
+ fake_callbacks_.push_back(new FakeAudioRenderCallback(step)); |
+ mixer_inputs_.push_back(new AudioRendererMixerInput( |
+ base::Bind(&AudioRendererMixerTest::GetMixer, |
+ base::Unretained(this)), |
+ base::Bind(&AudioRendererMixerTest::RemoveMixer, |
+ base::Unretained(this)), |
+ kDefaultDeviceId, kDefaultSecurityOrigin)); |
+ mixer_inputs_[input]->Initialize(input_parameters_[i], |
+ fake_callbacks_[input]); |
+ mixer_inputs_[input]->SetVolume(1.0f); |
+ } |
} |
EXPECT_CALL(*this, RemoveMixer(testing::_, testing::_, testing::_)) |
- .Times(count); |
+ .Times(mixer_inputs_.size()); |
} |
bool ValidateAudioData(int index, int frames, float scale, double epsilon) { |
@@ -112,9 +134,11 @@ class AudioRendererMixerTest |
for (int j = index; j < frames; j++) { |
double error = fabs(audio_bus_->channel(i)[j] - |
expected_audio_bus_->channel(i)[j] * scale); |
- if (error > epsilon) { |
+ // The second comparison is for the case when scale is set to 0 |
+ // (and less that 1 in general) |
+ if ((error > epsilon * scale) && (error > epsilon)) { |
EXPECT_NEAR(expected_audio_bus_->channel(i)[j] * scale, |
- audio_bus_->channel(i)[j], epsilon) |
+ audio_bus_->channel(i)[j], epsilon * scale) |
<< " i=" << i << ", j=" << j; |
return false; |
} |
@@ -279,13 +303,40 @@ class AudioRendererMixerTest |
EXPECT_TRUE(RenderAndValidateAudioData(0.0f)); |
} |
+ // Verify output when mixer inputs in mixed post-Stop() and post-Play() |
+ // states. |
+ void MixedStopPlayTest(int inputs) { |
+ InitializeInputs(inputs); |
+ |
+ // Start() all inputs. |
+ for (size_t i = 0; i < mixer_inputs_.size(); ++i) |
+ mixer_inputs_[i]->Start(); |
+ |
+ // Stop() all even numbered mixer inputs and Play() all odd numbered inputs |
+ // and ensure we get the right value. |
+ for (size_t i = 1; i < mixer_inputs_.size(); i += 2) { |
+ mixer_inputs_[i - 1]->Stop(); |
+ mixer_inputs_[i]->Play(); |
+ } |
+ |
+ // Stop the last input in case the number of inputs is odd |
+ if (mixer_inputs_.size() % 2) |
+ mixer_inputs_[mixer_inputs_.size() - 1]->Stop(); |
+ |
+ ASSERT_TRUE(RenderAndValidateAudioData( |
+ std::max(1.f, static_cast<float>(floor(mixer_inputs_.size() / 2.f))))); |
+ |
+ for (size_t i = 1; i < mixer_inputs_.size(); i += 2) |
+ mixer_inputs_[i]->Stop(); |
+ } |
+ |
protected: |
virtual ~AudioRendererMixerTest() {} |
scoped_refptr<MockAudioRendererSink> sink_; |
scoped_ptr<AudioRendererMixer> mixer_; |
AudioRendererSink::RenderCallback* mixer_callback_; |
- AudioParameters input_parameters_; |
+ std::vector<AudioParameters> input_parameters_; |
AudioParameters output_parameters_; |
scoped_ptr<AudioBus> audio_bus_; |
scoped_ptr<AudioBus> expected_audio_bus_; |
@@ -373,23 +424,13 @@ TEST_P(AudioRendererMixerTest, ManyInputStop) { |
// Test mixer with many inputs in mixed post-Stop() and post-Play() states. |
TEST_P(AudioRendererMixerTest, ManyInputMixedStopPlay) { |
- InitializeInputs(kMixerInputs); |
- |
- // Start() all inputs. |
- for (size_t i = 0; i < mixer_inputs_.size(); ++i) |
- mixer_inputs_[i]->Start(); |
- |
- // Stop() all even numbered mixer inputs and Play() all odd numbered inputs |
- // and ensure we get the right value. |
- for (size_t i = 1; i < mixer_inputs_.size(); i += 2) { |
- mixer_inputs_[i - 1]->Stop(); |
- mixer_inputs_[i]->Play(); |
- } |
- ASSERT_TRUE(RenderAndValidateAudioData(std::max( |
- mixer_inputs_.size() / 2, static_cast<size_t>(1)))); |
+ MixedStopPlayTest(kMixerInputs); |
+} |
- for (size_t i = 1; i < mixer_inputs_.size(); i += 2) |
- mixer_inputs_[i]->Stop(); |
+// Test mixer with many inputs in mixed post-Stop() and post-Play() states. |
+TEST_P(AudioRendererMixerTest, ManyInputMixedStopPlayOdd) { |
+ // Odd number of inputs per sample rate, to stop them unevenly. |
+ MixedStopPlayTest(kOddMixerInputs); |
} |
TEST_P(AudioRendererMixerBehavioralTest, OnRenderError) { |
@@ -474,22 +515,36 @@ TEST_P(AudioRendererMixerBehavioralTest, MixerPausesStream) { |
} |
INSTANTIATE_TEST_CASE_P( |
- AudioRendererMixerTest, AudioRendererMixerTest, testing::Values( |
- // No resampling. |
- std::tr1::make_tuple(44100, 44100, 0.00000048), |
+ AudioRendererMixerTest, |
+ AudioRendererMixerTest, |
+ testing::Values( |
+ // No resampling, 1 input sample rate. |
+ std::tr1::make_tuple(kTestInputLower, kTestInputLower[0], 0.00000048), |
- // Upsampling. |
- std::tr1::make_tuple(44100, 48000, 0.033), |
+ // Upsampling, 1 input sample rate. |
+ std::tr1::make_tuple(kTestInputLower, kTestInputHigher[0], 0.01), |
- // Downsampling. |
- std::tr1::make_tuple(48000, 41000, 0.042))); |
+ // Downsampling, 1 input sample rate. |
+ std::tr1::make_tuple(kTestInputHigher, kTestInputLower[0], 0.01), |
+ |
+ // Downsampling, multuple input sample rates. |
+ std::tr1::make_tuple(kTestInput3Rates, kTestInput3Rates[0], 0.01), |
+ |
+ // Upsampling, multiple sinput sample rates. |
+ std::tr1::make_tuple(kTestInput3Rates, kTestInput3Rates[2], 0.01), |
+ |
+ // Both downsampling and upsampling, multiple input sample rates |
+ std::tr1::make_tuple(kTestInput3Rates, kTestInput3Rates[1], 0.01))); |
// Test cases for behavior which is independent of parameters. Values() doesn't |
// support single item lists and we don't want these test cases to run for every |
// parameter set. |
INSTANTIATE_TEST_CASE_P( |
- AudioRendererMixerBehavioralTest, AudioRendererMixerBehavioralTest, |
+ AudioRendererMixerBehavioralTest, |
+ AudioRendererMixerBehavioralTest, |
testing::ValuesIn(std::vector<AudioRendererMixerTestData>( |
- 1, std::tr1::make_tuple(44100, 44100, 0)))); |
- |
+ 1, |
+ std::tr1::make_tuple(kTestInputLower, |
+ kTestInputLower[0], |
+ 0.00000048)))); |
} // namespace media |