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 <list>
      6 
      7 #include "base/bind.h"
      8 #include "base/bind_helpers.h"
      9 #include "base/rand_util.h"
     10 #include "base/synchronization/waitable_event.h"
     11 #include "base/threading/thread.h"
     12 #include "media/audio/audio_io.h"
     13 #include "media/audio/simple_sources.h"
     14 #include "media/audio/virtual_audio_input_stream.h"
     15 #include "media/audio/virtual_audio_output_stream.h"
     16 #include "testing/gmock/include/gmock/gmock.h"
     17 #include "testing/gtest/include/gtest/gtest.h"
     18 
     19 using ::testing::_;
     20 using ::testing::AtLeast;
     21 using ::testing::InvokeWithoutArgs;
     22 using ::testing::NotNull;
     23 
     24 namespace media {
     25 
     26 namespace {
     27 
     28 const AudioParameters kParams(
     29     AudioParameters::AUDIO_PCM_LOW_LATENCY, CHANNEL_LAYOUT_STEREO, 8000, 8, 10);
     30 
     31 class MockInputCallback : public AudioInputStream::AudioInputCallback {
     32  public:
     33   MockInputCallback()
     34       : data_pushed_(false, false) {
     35     ON_CALL(*this, OnData(_, _, _, _)).WillByDefault(
     36         InvokeWithoutArgs(&data_pushed_, &base::WaitableEvent::Signal));
     37   }
     38 
     39   virtual ~MockInputCallback() {}
     40 
     41   MOCK_METHOD4(OnData,
     42                void(AudioInputStream* stream,
     43                     const AudioBus* source,
     44                     uint32 hardware_delay_bytes,
     45                     double volume));
     46   MOCK_METHOD1(OnError, void(AudioInputStream* stream));
     47 
     48   void WaitForDataPushes() {
     49     for (int i = 0; i < 3; ++i) {
     50       data_pushed_.Wait();
     51     }
     52   }
     53 
     54  private:
     55   base::WaitableEvent data_pushed_;
     56 
     57   DISALLOW_COPY_AND_ASSIGN(MockInputCallback);
     58 };
     59 
     60 class TestAudioSource : public SineWaveAudioSource {
     61  public:
     62   TestAudioSource()
     63       : SineWaveAudioSource(
     64             kParams.channel_layout(), 200.0, kParams.sample_rate()),
     65         data_pulled_(false, false) {}
     66 
     67   virtual ~TestAudioSource() {}
     68 
     69   virtual int OnMoreData(AudioBus* audio_bus,
     70                          AudioBuffersState audio_buffers) OVERRIDE {
     71     const int ret = SineWaveAudioSource::OnMoreData(audio_bus, audio_buffers);
     72     data_pulled_.Signal();
     73     return ret;
     74   }
     75 
     76   void WaitForDataPulls() {
     77     for (int i = 0; i < 3; ++i) {
     78       data_pulled_.Wait();
     79     }
     80   }
     81 
     82  private:
     83   base::WaitableEvent data_pulled_;
     84 
     85   DISALLOW_COPY_AND_ASSIGN(TestAudioSource);
     86 };
     87 
     88 }  // namespace
     89 
     90 class VirtualAudioInputStreamTest : public testing::TestWithParam<bool> {
     91  public:
     92   VirtualAudioInputStreamTest()
     93       : audio_thread_(new base::Thread("AudioThread")),
     94         worker_thread_(new base::Thread("AudioWorkerThread")),
     95         stream_(NULL),
     96         closed_stream_(false, false) {
     97     audio_thread_->Start();
     98     audio_task_runner_ = audio_thread_->message_loop_proxy();
     99   }
    100 
    101   virtual ~VirtualAudioInputStreamTest() {
    102     SyncWithAudioThread();
    103 
    104     DCHECK(output_streams_.empty());
    105     DCHECK(stopped_output_streams_.empty());
    106   }
    107 
    108   void Create() {
    109     const bool worker_is_separate_thread = GetParam();
    110     stream_ = new VirtualAudioInputStream(
    111         kParams, GetWorkerTaskRunner(worker_is_separate_thread),
    112         base::Bind(&base::DeletePointer<VirtualAudioInputStream>));
    113     stream_->Open();
    114   }
    115 
    116   void Start() {
    117     EXPECT_CALL(input_callback_, OnData(_, NotNull(), _, _)).Times(AtLeast(1));
    118 
    119     ASSERT_TRUE(!!stream_);
    120     stream_->Start(&input_callback_);
    121   }
    122 
    123   void CreateAndStartOneOutputStream() {
    124     ASSERT_TRUE(!!stream_);
    125     AudioOutputStream* const output_stream = new VirtualAudioOutputStream(
    126         kParams,
    127         stream_,
    128         base::Bind(&base::DeletePointer<VirtualAudioOutputStream>));
    129     output_streams_.push_back(output_stream);
    130 
    131     output_stream->Open();
    132     output_stream->Start(&source_);
    133   }
    134 
    135   void Stop() {
    136     ASSERT_TRUE(!!stream_);
    137     stream_->Stop();
    138   }
    139 
    140   void Close() {
    141     ASSERT_TRUE(!!stream_);
    142     stream_->Close();
    143     stream_ = NULL;
    144     closed_stream_.Signal();
    145   }
    146 
    147   void WaitForDataToFlow() {
    148     // Wait until audio thread is idle before calling output_streams_.size().
    149     SyncWithAudioThread();
    150 
    151     const int count = output_streams_.size();
    152     for (int i = 0; i < count; ++i) {
    153       source_.WaitForDataPulls();
    154     }
    155 
    156     input_callback_.WaitForDataPushes();
    157   }
    158 
    159   void WaitUntilClosed() {
    160     closed_stream_.Wait();
    161   }
    162 
    163   void StopAndCloseOneOutputStream() {
    164     ASSERT_TRUE(!output_streams_.empty());
    165     AudioOutputStream* const output_stream = output_streams_.front();
    166     ASSERT_TRUE(!!output_stream);
    167     output_streams_.pop_front();
    168 
    169     output_stream->Stop();
    170     output_stream->Close();
    171   }
    172 
    173   void StopFirstOutputStream() {
    174     ASSERT_TRUE(!output_streams_.empty());
    175     AudioOutputStream* const output_stream = output_streams_.front();
    176     ASSERT_TRUE(!!output_stream);
    177     output_streams_.pop_front();
    178     output_stream->Stop();
    179     stopped_output_streams_.push_back(output_stream);
    180   }
    181 
    182   void StopSomeOutputStreams() {
    183     ASSERT_LE(2, static_cast<int>(output_streams_.size()));
    184     for (int remaning = base::RandInt(1, output_streams_.size() - 1);
    185          remaning > 0; --remaning) {
    186       StopFirstOutputStream();
    187     }
    188   }
    189 
    190   void RestartAllStoppedOutputStreams() {
    191     typedef std::list<AudioOutputStream*>::const_iterator ConstIter;
    192     for (ConstIter it = stopped_output_streams_.begin();
    193          it != stopped_output_streams_.end(); ++it) {
    194       (*it)->Start(&source_);
    195       output_streams_.push_back(*it);
    196     }
    197     stopped_output_streams_.clear();
    198   }
    199 
    200   const scoped_refptr<base::SingleThreadTaskRunner>& audio_task_runner() const {
    201     return audio_task_runner_;
    202   }
    203 
    204   const scoped_refptr<base::SingleThreadTaskRunner>& GetWorkerTaskRunner(
    205       bool worker_is_separate_thread) {
    206     if (worker_is_separate_thread) {
    207       if (!worker_thread_->IsRunning()) {
    208         worker_thread_->Start();
    209         worker_task_runner_ = worker_thread_->message_loop_proxy();
    210       }
    211       return worker_task_runner_;
    212     } else {
    213       return audio_task_runner_;
    214     }
    215   }
    216 
    217  private:
    218   void SyncWithAudioThread() {
    219     base::WaitableEvent done(false, false);
    220     audio_task_runner_->PostTask(
    221         FROM_HERE,
    222         base::Bind(&base::WaitableEvent::Signal, base::Unretained(&done)));
    223     done.Wait();
    224   }
    225 
    226   scoped_ptr<base::Thread> audio_thread_;
    227   scoped_refptr<base::SingleThreadTaskRunner> audio_task_runner_;
    228   scoped_ptr<base::Thread> worker_thread_;
    229   scoped_refptr<base::SingleThreadTaskRunner> worker_task_runner_;
    230 
    231   VirtualAudioInputStream* stream_;
    232   MockInputCallback input_callback_;
    233   base::WaitableEvent closed_stream_;
    234 
    235   std::list<AudioOutputStream*> output_streams_;
    236   std::list<AudioOutputStream*> stopped_output_streams_;
    237   TestAudioSource source_;
    238 
    239   DISALLOW_COPY_AND_ASSIGN(VirtualAudioInputStreamTest);
    240 };
    241 
    242 #define RUN_ON_AUDIO_THREAD(method)  \
    243   audio_task_runner()->PostTask(  \
    244       FROM_HERE, base::Bind(&VirtualAudioInputStreamTest::method,  \
    245                             base::Unretained(this)))
    246 
    247 TEST_P(VirtualAudioInputStreamTest, CreateAndClose) {
    248   RUN_ON_AUDIO_THREAD(Create);
    249   RUN_ON_AUDIO_THREAD(Close);
    250   WaitUntilClosed();
    251 }
    252 
    253 TEST_P(VirtualAudioInputStreamTest, NoOutputs) {
    254   RUN_ON_AUDIO_THREAD(Create);
    255   RUN_ON_AUDIO_THREAD(Start);
    256   WaitForDataToFlow();
    257   RUN_ON_AUDIO_THREAD(Stop);
    258   RUN_ON_AUDIO_THREAD(Close);
    259   WaitUntilClosed();
    260 }
    261 
    262 TEST_P(VirtualAudioInputStreamTest, SingleOutput) {
    263   RUN_ON_AUDIO_THREAD(Create);
    264   RUN_ON_AUDIO_THREAD(Start);
    265   RUN_ON_AUDIO_THREAD(CreateAndStartOneOutputStream);
    266   WaitForDataToFlow();
    267   RUN_ON_AUDIO_THREAD(StopAndCloseOneOutputStream);
    268   RUN_ON_AUDIO_THREAD(Stop);
    269   RUN_ON_AUDIO_THREAD(Close);
    270   WaitUntilClosed();
    271 }
    272 
    273 TEST_P(VirtualAudioInputStreamTest, SingleOutputPausedAndRestarted) {
    274   RUN_ON_AUDIO_THREAD(Create);
    275   RUN_ON_AUDIO_THREAD(Start);
    276   RUN_ON_AUDIO_THREAD(CreateAndStartOneOutputStream);
    277   WaitForDataToFlow();
    278   RUN_ON_AUDIO_THREAD(StopFirstOutputStream);
    279   RUN_ON_AUDIO_THREAD(RestartAllStoppedOutputStreams);
    280   WaitForDataToFlow();
    281   RUN_ON_AUDIO_THREAD(StopAndCloseOneOutputStream);
    282   RUN_ON_AUDIO_THREAD(Stop);
    283   RUN_ON_AUDIO_THREAD(Close);
    284   WaitUntilClosed();
    285 }
    286 
    287 TEST_P(VirtualAudioInputStreamTest, MultipleOutputs) {
    288   RUN_ON_AUDIO_THREAD(Create);
    289   RUN_ON_AUDIO_THREAD(Start);
    290   RUN_ON_AUDIO_THREAD(CreateAndStartOneOutputStream);
    291   WaitForDataToFlow();
    292   RUN_ON_AUDIO_THREAD(CreateAndStartOneOutputStream);
    293   RUN_ON_AUDIO_THREAD(CreateAndStartOneOutputStream);
    294   WaitForDataToFlow();
    295   RUN_ON_AUDIO_THREAD(StopFirstOutputStream);
    296   RUN_ON_AUDIO_THREAD(StopFirstOutputStream);
    297   WaitForDataToFlow();
    298   RUN_ON_AUDIO_THREAD(StopFirstOutputStream);
    299   RUN_ON_AUDIO_THREAD(RestartAllStoppedOutputStreams);
    300   WaitForDataToFlow();
    301   RUN_ON_AUDIO_THREAD(StopAndCloseOneOutputStream);
    302   RUN_ON_AUDIO_THREAD(StopAndCloseOneOutputStream);
    303   RUN_ON_AUDIO_THREAD(Stop);
    304   RUN_ON_AUDIO_THREAD(StopAndCloseOneOutputStream);
    305   RUN_ON_AUDIO_THREAD(Close);
    306   WaitUntilClosed();
    307 }
    308 
    309 // A combination of all of the above tests with many output streams.
    310 TEST_P(VirtualAudioInputStreamTest, ComprehensiveTest) {
    311   static const int kNumOutputs = 8;
    312   static const int kHalfNumOutputs = kNumOutputs / 2;
    313   static const int kPauseIterations = 5;
    314 
    315   RUN_ON_AUDIO_THREAD(Create);
    316   for (int i = 0; i < kHalfNumOutputs; ++i) {
    317     RUN_ON_AUDIO_THREAD(CreateAndStartOneOutputStream);
    318   }
    319   RUN_ON_AUDIO_THREAD(Start);
    320   WaitForDataToFlow();
    321   for (int i = 0; i < kHalfNumOutputs; ++i) {
    322     RUN_ON_AUDIO_THREAD(CreateAndStartOneOutputStream);
    323   }
    324   WaitForDataToFlow();
    325   for (int i = 0; i < kPauseIterations; ++i) {
    326     RUN_ON_AUDIO_THREAD(StopSomeOutputStreams);
    327     WaitForDataToFlow();
    328     RUN_ON_AUDIO_THREAD(RestartAllStoppedOutputStreams);
    329     WaitForDataToFlow();
    330   }
    331   for (int i = 0; i < kHalfNumOutputs; ++i) {
    332     RUN_ON_AUDIO_THREAD(StopAndCloseOneOutputStream);
    333   }
    334   RUN_ON_AUDIO_THREAD(Stop);
    335   for (int i = 0; i < kHalfNumOutputs; ++i) {
    336     RUN_ON_AUDIO_THREAD(StopAndCloseOneOutputStream);
    337   }
    338   RUN_ON_AUDIO_THREAD(Close);
    339   WaitUntilClosed();
    340 }
    341 
    342 INSTANTIATE_TEST_CASE_P(SingleVersusMultithreaded,
    343                         VirtualAudioInputStreamTest,
    344                         ::testing::Values(false, true));
    345 
    346 }  // namespace media
    347