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