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