Index: media/audio/fake_audio_consumer_unittest.cc |
diff --git a/media/audio/fake_audio_consumer_unittest.cc b/media/audio/fake_audio_consumer_unittest.cc |
index 362686cd6fb01b9d3887ef99b0e052339c337a30..39f99a8fa1a3c744438146b018e9c64cf9a1b5cd 100644 |
--- a/media/audio/fake_audio_consumer_unittest.cc |
+++ b/media/audio/fake_audio_consumer_unittest.cc |
@@ -2,18 +2,39 @@ |
// Use of this source code is governed by a BSD-style license that can be |
// found in the LICENSE file. |
+#include <cmath> |
+ |
#include "base/bind.h" |
+#include "base/command_line.h" |
#include "base/message_loop.h" |
+#include "base/rand_util.h" |
+#include "base/run_loop.h" |
+#include "base/string_number_conversions.h" |
+#include "base/string_util.h" |
+#include "base/stringprintf.h" |
#include "base/time.h" |
#include "media/audio/audio_buffers_state.h" |
#include "media/audio/fake_audio_consumer.h" |
#include "media/audio/simple_sources.h" |
+#include "media/base/audio_converter.h" |
#include "testing/gtest/include/gtest/gtest.h" |
namespace media { |
static const int kTestCallbacks = 5; |
+// Switch to choose the runtime for the jitter test. |
+static const char kJitterRunTime[] = "jitter-runtime"; |
+static const int kDefaultJitterRunTimeSeconds = 2; |
+ |
+// Switch to choose the buffer size or to emulate an OS for output buffer size. |
+// Valid values are <size_t>, WIN, MAC, LINUX. |
+static const char kJitterOutputSize[] = "jitter-output-size"; |
+ |
+// Input buffer size. |
+static const char kJitterInputSize[] = "jitter-input-size"; |
+static const int kDefaultJitterInputBufferSize = 2048; |
+ |
class FakeAudioConsumerTest : public testing::Test { |
public: |
FakeAudioConsumerTest() |
@@ -139,4 +160,174 @@ TEST_F(FakeAudioConsumerTest, StartStopClearsCallbacks) { |
message_loop_.Run(); |
} |
+class JitterTest : public testing::Test, public AudioConverter::InputCallback { |
+ public: |
+ enum BufferSizeChoice { kCustom, kMac, kWin, kLinux }; |
+ |
+ JitterTest() { |
+ std::string output_size( |
+ CommandLine::ForCurrentProcess()->GetSwitchValueASCII( |
+ kJitterOutputSize)); |
+ if (LowerCaseEqualsASCII(output_size, "win")) { |
+ buffer_size_choice_ = kWin; |
+ } else if (LowerCaseEqualsASCII(output_size, "linux")) { |
+ buffer_size_choice_ = kLinux; |
+ } else if (LowerCaseEqualsASCII(output_size, "mac")) { |
+ buffer_size_choice_ = kMac; |
+ } else if (base::StringToInt(output_size, &custom_output_buffer_size_)) { |
+ buffer_size_choice_ = kCustom; |
+ } else { |
+ buffer_size_choice_ = kCustom; |
+ custom_output_buffer_size_ = kDefaultJitterInputBufferSize; |
+ } |
+ |
+ std::string input_size( |
+ CommandLine::ForCurrentProcess()->GetSwitchValueASCII( |
+ kJitterInputSize)); |
+ if (!base::StringToInt(input_size, &input_buffer_size_)) |
+ input_buffer_size_ = kDefaultJitterInputBufferSize; |
+ |
+ std::string jitter_run_time( |
+ CommandLine::ForCurrentProcess()->GetSwitchValueASCII( |
+ kJitterRunTime)); |
+ if (!base::StringToInt(jitter_run_time, &jitter_run_time_secs_)) |
+ jitter_run_time_secs_ = kDefaultJitterRunTimeSeconds; |
+ } |
+ |
+ virtual ~JitterTest() {} |
+ |
+ base::TimeDelta ExpectedTimeBetweenCallbacks(const AudioParameters& params) { |
+ return base::TimeDelta::FromMicroseconds( |
+ params.frames_per_buffer() * base::Time::kMicrosecondsPerSecond / |
+ static_cast<float>(params.sample_rate())); |
+ } |
+ |
+ int ChooseOutputBufferSize(int output_sample_rate) { |
+ switch (buffer_size_choice_) { |
+ case kCustom: |
+ return custom_output_buffer_size_; |
+ case kMac: { |
+ int buffer_size = 128; |
+ if (output_sample_rate > 48000) { |
+ // The default buffer size is too small for higher sample rates and |
+ // may lead to glitching. Adjust upwards by multiples of the default |
+ // size. |
+ if (output_sample_rate <= 96000) |
+ buffer_size *= 2; |
+ else if (output_sample_rate <= 192000) |
+ buffer_size *= 4; |
+ } |
+ return buffer_size; |
+ } |
+ case kWin: |
+ return output_sample_rate / 100; |
+ case kLinux: |
+ return 512; |
+ } |
+ } |
+ |
+ int ChooseInputBufferSize(float input_sample_rate, int output_buffer_size, |
+ float output_sample_rate) { |
+ return input_buffer_size_; |
+ } |
+ |
+ virtual double ProvideInput(AudioBus* audio_bus, |
+ base::TimeDelta buffer_delay) { |
+ if (first_run_) { |
+ first_run_ = false; |
+ last_call_ = base::Time::Now(); |
+ } else { |
+ base::Time now = base::Time::Now(); |
+ time_between_callbacks_.push_back(now - last_call_); |
+ last_call_ = now; |
+ } |
+ |
+ if (base::Time::Now() - start_ > |
+ base::TimeDelta::FromSeconds(jitter_run_time_secs_)) { |
+ consumer_->Stop(); |
+ run_loop_->Quit(); |
+ } |
+ |
+ return 0; |
+ } |
+ |
+ protected: |
+ MessageLoop message_loop_; |
+ base::Time last_call_; |
+ base::Time start_; |
+ std::vector<base::TimeDelta> time_between_callbacks_; |
+ scoped_ptr<FakeAudioConsumer> consumer_; |
+ scoped_ptr<base::RunLoop> run_loop_; |
+ bool first_run_; |
+ BufferSizeChoice buffer_size_choice_; |
+ int input_buffer_size_; |
+ int custom_output_buffer_size_; |
+ int jitter_run_time_secs_; |
+ |
+ private: |
+ DISALLOW_COPY_AND_ASSIGN(JitterTest); |
+}; |
+ |
+TEST_F(JitterTest, Jitter) { |
+ static const int kInputRates[] = |
+ { 44100, 48000 }; |
+ static const int kOutputRates[] = |
+ { 16000, 44100, 48000, 96000, 192000 }; |
+ |
+ MessageLoop message_loop; |
+ for (size_t i = 0; i < arraysize(kInputRates); ++i) { |
+ for (size_t j = 0; j < arraysize(kOutputRates); ++j) { |
+ const int output_buffer_size = ChooseOutputBufferSize(kOutputRates[j]); |
+ const int input_buffer_size = ChooseInputBufferSize( |
+ kInputRates[i], output_buffer_size, kOutputRates[j]); |
+ |
+ const AudioParameters input_params( |
+ AudioParameters::AUDIO_FAKE, CHANNEL_LAYOUT_STEREO, |
+ kInputRates[i], 16, input_buffer_size); |
+ const AudioParameters output_params( |
+ AudioParameters::AUDIO_FAKE, CHANNEL_LAYOUT_STEREO, |
+ kOutputRates[j], 16, output_buffer_size); |
+ |
+ consumer_.reset(new FakeAudioConsumer( |
+ message_loop.message_loop_proxy(), output_params)); |
+ AudioConverter converter(input_params, output_params, false); |
+ converter.AddInput(this); |
+ consumer_->Start( |
+ base::Bind(&AudioConverter::Convert, base::Unretained(&converter))); |
+ run_loop_.reset(new base::RunLoop()); |
+ start_ = base::Time::Now(); |
+ first_run_ = true; |
+ run_loop_->Run(); |
+ |
+ base::TimeDelta min = base::TimeDelta::FromSeconds(10000); |
+ base::TimeDelta max = base::TimeDelta::FromSeconds(-10000); |
+ base::TimeDelta avg; |
+ int bad = 0; |
+ for (size_t k = 0; k < time_between_callbacks_.size(); ++k) { |
+ base::TimeDelta sample = time_between_callbacks_[k]; |
+ if (sample < min) |
+ min = sample; |
+ else if (sample > max) |
+ max = sample; |
+ avg += sample; |
+ if (sample < base::TimeDelta::FromMilliseconds(5)) |
+ bad++; |
+ } |
+ avg /= time_between_callbacks_.size(); |
+ |
+ printf( |
+ "rate=%d -> %d, size=%d -> %d, %d callbacks, %d bad, min=%f, " |
+ "max=%f, avg=%f, expected=%f\n", |
+ input_params.sample_rate(), output_params.sample_rate(), |
+ input_params.frames_per_buffer(), output_params.frames_per_buffer(), |
+ static_cast<int>(time_between_callbacks_.size()), bad, |
+ min.InMillisecondsF(), max.InMillisecondsF(), avg.InMillisecondsF(), |
+ ExpectedTimeBetweenCallbacks(input_params).InMillisecondsF()); |
+ |
+ time_between_callbacks_.clear(); |
+ |
+ } |
+ } |
+} |
+ |
} // namespace media |