Home | History | Annotate | Download | only in audio
      1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
      2 // Use of this source code is governed by a BSD-style license that can be
      3 // found in the LICENSE file.
      4 
      5 #include "base/bind.h"
      6 #include "base/message_loop/message_loop.h"
      7 #include "base/time/time.h"
      8 #include "media/audio/audio_buffers_state.h"
      9 #include "media/audio/audio_parameters.h"
     10 #include "media/audio/fake_audio_consumer.h"
     11 #include "media/audio/simple_sources.h"
     12 #include "testing/gtest/include/gtest/gtest.h"
     13 
     14 namespace media {
     15 
     16 static const int kTestCallbacks = 5;
     17 
     18 class FakeAudioConsumerTest : public testing::Test {
     19  public:
     20   FakeAudioConsumerTest()
     21       : params_(
     22             AudioParameters::AUDIO_FAKE, CHANNEL_LAYOUT_STEREO, 44100, 8, 128),
     23         fake_consumer_(message_loop_.message_loop_proxy(), params_),
     24         source_(params_.channels(), 200.0, params_.sample_rate()) {
     25     time_between_callbacks_ = base::TimeDelta::FromMicroseconds(
     26         params_.frames_per_buffer() * base::Time::kMicrosecondsPerSecond /
     27         static_cast<float>(params_.sample_rate()));
     28   }
     29 
     30   virtual ~FakeAudioConsumerTest() {}
     31 
     32   void ConsumeData(AudioBus* audio_bus) {
     33     source_.OnMoreData(audio_bus, AudioBuffersState());
     34   }
     35 
     36   void RunOnAudioThread() {
     37     ASSERT_TRUE(message_loop_.message_loop_proxy()->BelongsToCurrentThread());
     38     fake_consumer_.Start(base::Bind(
     39         &FakeAudioConsumerTest::ConsumeData, base::Unretained(this)));
     40   }
     41 
     42   void RunOnceOnAudioThread() {
     43     ASSERT_TRUE(message_loop_.message_loop_proxy()->BelongsToCurrentThread());
     44     RunOnAudioThread();
     45     // Start() should immediately post a task to run the source callback, so we
     46     // should end up with only a single callback being run.
     47     message_loop_.PostTask(FROM_HERE, base::Bind(
     48         &FakeAudioConsumerTest::EndTest, base::Unretained(this), 1));
     49   }
     50 
     51   void StopStartOnAudioThread() {
     52     ASSERT_TRUE(message_loop_.message_loop_proxy()->BelongsToCurrentThread());
     53     fake_consumer_.Stop();
     54     RunOnAudioThread();
     55   }
     56 
     57   void TimeCallbacksOnAudioThread(int callbacks) {
     58     ASSERT_TRUE(message_loop_.message_loop_proxy()->BelongsToCurrentThread());
     59 
     60     if (source_.callbacks() == 0) {
     61       RunOnAudioThread();
     62       start_time_ = base::TimeTicks::Now();
     63     }
     64 
     65     // Keep going until we've seen the requested number of callbacks.
     66     if (source_.callbacks() < callbacks) {
     67       message_loop_.PostDelayedTask(FROM_HERE, base::Bind(
     68           &FakeAudioConsumerTest::TimeCallbacksOnAudioThread,
     69           base::Unretained(this), callbacks), time_between_callbacks_ / 2);
     70     } else {
     71       end_time_ = base::TimeTicks::Now();
     72       EndTest(callbacks);
     73     }
     74   }
     75 
     76   void EndTest(int callbacks) {
     77     ASSERT_TRUE(message_loop_.message_loop_proxy()->BelongsToCurrentThread());
     78     fake_consumer_.Stop();
     79     EXPECT_LE(callbacks, source_.callbacks());
     80     message_loop_.PostTask(FROM_HERE, base::MessageLoop::QuitClosure());
     81   }
     82 
     83  protected:
     84   base::MessageLoop message_loop_;
     85   AudioParameters params_;
     86   FakeAudioConsumer fake_consumer_;
     87   SineWaveAudioSource source_;
     88   base::TimeTicks start_time_;
     89   base::TimeTicks end_time_;
     90   base::TimeDelta time_between_callbacks_;
     91 
     92  private:
     93   DISALLOW_COPY_AND_ASSIGN(FakeAudioConsumerTest);
     94 };
     95 
     96 // Ensure the fake audio stream runs on the audio thread and handles fires
     97 // callbacks to the AudioSourceCallback.
     98 TEST_F(FakeAudioConsumerTest, FakeStreamBasicCallback) {
     99   message_loop_.PostTask(FROM_HERE, base::Bind(
    100       &FakeAudioConsumerTest::RunOnceOnAudioThread,
    101       base::Unretained(this)));
    102   message_loop_.Run();
    103 }
    104 
    105 // Ensure the time between callbacks is sane.
    106 TEST_F(FakeAudioConsumerTest, TimeBetweenCallbacks) {
    107   message_loop_.PostTask(FROM_HERE, base::Bind(
    108       &FakeAudioConsumerTest::TimeCallbacksOnAudioThread,
    109       base::Unretained(this), kTestCallbacks));
    110   message_loop_.Run();
    111 
    112   // There are only (kTestCallbacks - 1) intervals between kTestCallbacks.
    113   base::TimeDelta actual_time_between_callbacks =
    114       (end_time_ - start_time_) / (source_.callbacks() - 1);
    115 
    116   // Ensure callback time is no faster than the expected time between callbacks.
    117   EXPECT_TRUE(actual_time_between_callbacks >= time_between_callbacks_);
    118 
    119   // Softly check if the callback time is no slower than twice the expected time
    120   // between callbacks.  Since this test runs on the bots we can't be too strict
    121   // with the bounds.
    122   if (actual_time_between_callbacks > 2 * time_between_callbacks_)
    123     LOG(ERROR) << "Time between fake audio callbacks is too large!";
    124 }
    125 
    126 // Ensure Start()/Stop() on the stream doesn't generate too many callbacks.  See
    127 // http://crbug.com/159049
    128 TEST_F(FakeAudioConsumerTest, StartStopClearsCallbacks) {
    129   message_loop_.PostTask(FROM_HERE, base::Bind(
    130       &FakeAudioConsumerTest::TimeCallbacksOnAudioThread,
    131       base::Unretained(this), kTestCallbacks));
    132 
    133   // Issue a Stop() / Start() in between expected callbacks to maximize the
    134   // chance of catching the FakeAudioOutputStream doing the wrong thing.
    135   message_loop_.PostDelayedTask(FROM_HERE, base::Bind(
    136       &FakeAudioConsumerTest::StopStartOnAudioThread,
    137       base::Unretained(this)), time_between_callbacks_ / 2);
    138 
    139   // EndTest() will ensure the proper number of callbacks have occurred.
    140   message_loop_.Run();
    141 }
    142 
    143 }  // namespace media
    144