12a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// Copyright (c) 2012 The Chromium Authors. All rights reserved.
22a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be
32a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// found in the LICENSE file.
42a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
52a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include <list>
62a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
72a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "base/bind.h"
82a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "base/bind_helpers.h"
92a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "base/rand_util.h"
102a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "base/synchronization/waitable_event.h"
112a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "base/threading/thread.h"
122a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "media/audio/audio_io.h"
132a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "media/audio/simple_sources.h"
142a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "media/audio/virtual_audio_input_stream.h"
152a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "media/audio/virtual_audio_output_stream.h"
162a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "testing/gmock/include/gmock/gmock.h"
172a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "testing/gtest/include/gtest/gtest.h"
182a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
192a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)using ::testing::_;
202a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)using ::testing::AtLeast;
212a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)using ::testing::InvokeWithoutArgs;
222a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)using ::testing::NotNull;
232a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
242a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)namespace media {
252a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
262a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)namespace {
272a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
282a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)const AudioParameters kParams(
292a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    AudioParameters::AUDIO_PCM_LOW_LATENCY, CHANNEL_LAYOUT_STEREO, 8000, 8, 10);
302a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
312a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)class MockInputCallback : public AudioInputStream::AudioInputCallback {
322a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) public:
332a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  MockInputCallback()
342a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      : data_pushed_(false, false) {
356d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)    ON_CALL(*this, OnData(_, _, _, _)).WillByDefault(
366d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)        InvokeWithoutArgs(&data_pushed_, &base::WaitableEvent::Signal));
372a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
382a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
392a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  virtual ~MockInputCallback() {}
402a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
416d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)  MOCK_METHOD4(OnData,
426d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)               void(AudioInputStream* stream,
436d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)                    const AudioBus* source,
446d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)                    uint32 hardware_delay_bytes,
456d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)                    double volume));
462a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  MOCK_METHOD1(OnError, void(AudioInputStream* stream));
472a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
482a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  void WaitForDataPushes() {
492a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    for (int i = 0; i < 3; ++i) {
502a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      data_pushed_.Wait();
512a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    }
522a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
532a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
542a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) private:
552a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  base::WaitableEvent data_pushed_;
562a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
572a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  DISALLOW_COPY_AND_ASSIGN(MockInputCallback);
582a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)};
592a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
602a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)class TestAudioSource : public SineWaveAudioSource {
612a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) public:
622a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  TestAudioSource()
632a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      : SineWaveAudioSource(
642a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)            kParams.channel_layout(), 200.0, kParams.sample_rate()),
652a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        data_pulled_(false, false) {}
662a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
672a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  virtual ~TestAudioSource() {}
682a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
692a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  virtual int OnMoreData(AudioBus* audio_bus,
702a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                         AudioBuffersState audio_buffers) OVERRIDE {
712a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    const int ret = SineWaveAudioSource::OnMoreData(audio_bus, audio_buffers);
722a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    data_pulled_.Signal();
732a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return ret;
742a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
752a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
762a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  void WaitForDataPulls() {
772a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    for (int i = 0; i < 3; ++i) {
782a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      data_pulled_.Wait();
792a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    }
802a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
812a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
822a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) private:
832a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  base::WaitableEvent data_pulled_;
842a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
852a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  DISALLOW_COPY_AND_ASSIGN(TestAudioSource);
862a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)};
872a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
882a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}  // namespace
892a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
90eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdochclass VirtualAudioInputStreamTest : public testing::TestWithParam<bool> {
912a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) public:
922a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  VirtualAudioInputStreamTest()
932a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      : audio_thread_(new base::Thread("AudioThread")),
94eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch        worker_thread_(new base::Thread("AudioWorkerThread")),
952a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        stream_(NULL),
962a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        closed_stream_(false, false) {
972a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    audio_thread_->Start();
985d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    audio_task_runner_ = audio_thread_->message_loop_proxy();
992a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
1002a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1012a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  virtual ~VirtualAudioInputStreamTest() {
1022a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    SyncWithAudioThread();
1032a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1042a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    DCHECK(output_streams_.empty());
1052a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    DCHECK(stopped_output_streams_.empty());
1062a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
1072a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1082a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  void Create() {
109eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    const bool worker_is_separate_thread = GetParam();
1102a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    stream_ = new VirtualAudioInputStream(
1115d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        kParams, GetWorkerTaskRunner(worker_is_separate_thread),
1122a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        base::Bind(&base::DeletePointer<VirtualAudioInputStream>));
1132a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    stream_->Open();
1142a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
1152a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1162a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  void Start() {
1176d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)    EXPECT_CALL(input_callback_, OnData(_, NotNull(), _, _)).Times(AtLeast(1));
1182a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1192a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    ASSERT_TRUE(!!stream_);
1202a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    stream_->Start(&input_callback_);
1212a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
1222a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1232a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  void CreateAndStartOneOutputStream() {
1242a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    ASSERT_TRUE(!!stream_);
125868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    AudioOutputStream* const output_stream = new VirtualAudioOutputStream(
126868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)        kParams,
127868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)        stream_,
128868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)        base::Bind(&base::DeletePointer<VirtualAudioOutputStream>));
1292a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    output_streams_.push_back(output_stream);
1302a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1312a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    output_stream->Open();
1322a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    output_stream->Start(&source_);
1332a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
1342a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1352a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  void Stop() {
1362a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    ASSERT_TRUE(!!stream_);
1372a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    stream_->Stop();
1382a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
1392a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1402a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  void Close() {
1412a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    ASSERT_TRUE(!!stream_);
1422a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    stream_->Close();
1432a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    stream_ = NULL;
1442a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    closed_stream_.Signal();
1452a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
1462a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1472a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  void WaitForDataToFlow() {
1482a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    // Wait until audio thread is idle before calling output_streams_.size().
1492a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    SyncWithAudioThread();
1502a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1512a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    const int count = output_streams_.size();
1522a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    for (int i = 0; i < count; ++i) {
1532a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      source_.WaitForDataPulls();
1542a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    }
1552a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1562a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    input_callback_.WaitForDataPushes();
1572a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
1582a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1592a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  void WaitUntilClosed() {
1602a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    closed_stream_.Wait();
1612a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
1622a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1632a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  void StopAndCloseOneOutputStream() {
1642a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    ASSERT_TRUE(!output_streams_.empty());
1652a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    AudioOutputStream* const output_stream = output_streams_.front();
1662a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    ASSERT_TRUE(!!output_stream);
1672a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    output_streams_.pop_front();
1682a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1692a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    output_stream->Stop();
1702a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    output_stream->Close();
1712a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
1722a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1732a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  void StopFirstOutputStream() {
1742a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    ASSERT_TRUE(!output_streams_.empty());
1752a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    AudioOutputStream* const output_stream = output_streams_.front();
1762a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    ASSERT_TRUE(!!output_stream);
1772a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    output_streams_.pop_front();
1782a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    output_stream->Stop();
1792a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    stopped_output_streams_.push_back(output_stream);
1802a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
1812a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1822a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  void StopSomeOutputStreams() {
1832a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    ASSERT_LE(2, static_cast<int>(output_streams_.size()));
1842a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    for (int remaning = base::RandInt(1, output_streams_.size() - 1);
1852a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)         remaning > 0; --remaning) {
1862a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      StopFirstOutputStream();
1872a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    }
1882a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
1892a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1902a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  void RestartAllStoppedOutputStreams() {
1912a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    typedef std::list<AudioOutputStream*>::const_iterator ConstIter;
1922a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    for (ConstIter it = stopped_output_streams_.begin();
1932a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)         it != stopped_output_streams_.end(); ++it) {
1942a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      (*it)->Start(&source_);
1952a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      output_streams_.push_back(*it);
1962a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    }
1972a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    stopped_output_streams_.clear();
1982a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
1992a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
2005d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  const scoped_refptr<base::SingleThreadTaskRunner>& audio_task_runner() const {
2015d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    return audio_task_runner_;
2022a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
2032a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
2045d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  const scoped_refptr<base::SingleThreadTaskRunner>& GetWorkerTaskRunner(
205eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch      bool worker_is_separate_thread) {
206eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    if (worker_is_separate_thread) {
207eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch      if (!worker_thread_->IsRunning()) {
208eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch        worker_thread_->Start();
2095d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        worker_task_runner_ = worker_thread_->message_loop_proxy();
210eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch      }
2115d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      return worker_task_runner_;
212eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    } else {
2135d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      return audio_task_runner_;
214eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    }
215eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  }
216eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
2172a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) private:
2182a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  void SyncWithAudioThread() {
2192a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    base::WaitableEvent done(false, false);
2205d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    audio_task_runner_->PostTask(
2212a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        FROM_HERE,
2222a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        base::Bind(&base::WaitableEvent::Signal, base::Unretained(&done)));
2232a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    done.Wait();
2242a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
2252a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
2262a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  scoped_ptr<base::Thread> audio_thread_;
2275d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  scoped_refptr<base::SingleThreadTaskRunner> audio_task_runner_;
228eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  scoped_ptr<base::Thread> worker_thread_;
2295d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  scoped_refptr<base::SingleThreadTaskRunner> worker_task_runner_;
2302a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
2312a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  VirtualAudioInputStream* stream_;
2322a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  MockInputCallback input_callback_;
2332a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  base::WaitableEvent closed_stream_;
2342a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
2352a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  std::list<AudioOutputStream*> output_streams_;
2362a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  std::list<AudioOutputStream*> stopped_output_streams_;
2372a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  TestAudioSource source_;
2382a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
2392a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  DISALLOW_COPY_AND_ASSIGN(VirtualAudioInputStreamTest);
2402a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)};
2412a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
2422a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#define RUN_ON_AUDIO_THREAD(method)  \
2435d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  audio_task_runner()->PostTask(  \
2442a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      FROM_HERE, base::Bind(&VirtualAudioInputStreamTest::method,  \
2452a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                            base::Unretained(this)))
2462a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
247eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen MurdochTEST_P(VirtualAudioInputStreamTest, CreateAndClose) {
2482a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  RUN_ON_AUDIO_THREAD(Create);
2492a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  RUN_ON_AUDIO_THREAD(Close);
2502a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  WaitUntilClosed();
2512a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
2522a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
253eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen MurdochTEST_P(VirtualAudioInputStreamTest, NoOutputs) {
2542a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  RUN_ON_AUDIO_THREAD(Create);
2552a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  RUN_ON_AUDIO_THREAD(Start);
2562a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  WaitForDataToFlow();
2572a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  RUN_ON_AUDIO_THREAD(Stop);
2582a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  RUN_ON_AUDIO_THREAD(Close);
2592a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  WaitUntilClosed();
2602a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
2612a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
262eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen MurdochTEST_P(VirtualAudioInputStreamTest, SingleOutput) {
2632a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  RUN_ON_AUDIO_THREAD(Create);
2642a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  RUN_ON_AUDIO_THREAD(Start);
2652a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  RUN_ON_AUDIO_THREAD(CreateAndStartOneOutputStream);
2662a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  WaitForDataToFlow();
2672a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  RUN_ON_AUDIO_THREAD(StopAndCloseOneOutputStream);
2682a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  RUN_ON_AUDIO_THREAD(Stop);
2692a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  RUN_ON_AUDIO_THREAD(Close);
2702a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  WaitUntilClosed();
2712a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
2722a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
273eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen MurdochTEST_P(VirtualAudioInputStreamTest, SingleOutputPausedAndRestarted) {
2742a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  RUN_ON_AUDIO_THREAD(Create);
2752a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  RUN_ON_AUDIO_THREAD(Start);
2762a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  RUN_ON_AUDIO_THREAD(CreateAndStartOneOutputStream);
2772a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  WaitForDataToFlow();
2782a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  RUN_ON_AUDIO_THREAD(StopFirstOutputStream);
2792a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  RUN_ON_AUDIO_THREAD(RestartAllStoppedOutputStreams);
2802a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  WaitForDataToFlow();
2812a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  RUN_ON_AUDIO_THREAD(StopAndCloseOneOutputStream);
2822a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  RUN_ON_AUDIO_THREAD(Stop);
2832a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  RUN_ON_AUDIO_THREAD(Close);
2842a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  WaitUntilClosed();
2852a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
2862a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
287eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen MurdochTEST_P(VirtualAudioInputStreamTest, MultipleOutputs) {
2882a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  RUN_ON_AUDIO_THREAD(Create);
2892a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  RUN_ON_AUDIO_THREAD(Start);
2902a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  RUN_ON_AUDIO_THREAD(CreateAndStartOneOutputStream);
2912a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  WaitForDataToFlow();
2922a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  RUN_ON_AUDIO_THREAD(CreateAndStartOneOutputStream);
2932a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  RUN_ON_AUDIO_THREAD(CreateAndStartOneOutputStream);
2942a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  WaitForDataToFlow();
2952a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  RUN_ON_AUDIO_THREAD(StopFirstOutputStream);
2962a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  RUN_ON_AUDIO_THREAD(StopFirstOutputStream);
2972a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  WaitForDataToFlow();
2982a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  RUN_ON_AUDIO_THREAD(StopFirstOutputStream);
2992a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  RUN_ON_AUDIO_THREAD(RestartAllStoppedOutputStreams);
3002a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  WaitForDataToFlow();
3012a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  RUN_ON_AUDIO_THREAD(StopAndCloseOneOutputStream);
3022a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  RUN_ON_AUDIO_THREAD(StopAndCloseOneOutputStream);
3032a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  RUN_ON_AUDIO_THREAD(Stop);
3042a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  RUN_ON_AUDIO_THREAD(StopAndCloseOneOutputStream);
3052a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  RUN_ON_AUDIO_THREAD(Close);
3062a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  WaitUntilClosed();
3072a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
3082a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
3092a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// A combination of all of the above tests with many output streams.
310eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen MurdochTEST_P(VirtualAudioInputStreamTest, ComprehensiveTest) {
3112a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  static const int kNumOutputs = 8;
3122a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  static const int kHalfNumOutputs = kNumOutputs / 2;
3132a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  static const int kPauseIterations = 5;
3142a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
3152a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  RUN_ON_AUDIO_THREAD(Create);
3162a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  for (int i = 0; i < kHalfNumOutputs; ++i) {
3172a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    RUN_ON_AUDIO_THREAD(CreateAndStartOneOutputStream);
3182a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
3192a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  RUN_ON_AUDIO_THREAD(Start);
3202a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  WaitForDataToFlow();
3212a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  for (int i = 0; i < kHalfNumOutputs; ++i) {
3222a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    RUN_ON_AUDIO_THREAD(CreateAndStartOneOutputStream);
3232a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
3242a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  WaitForDataToFlow();
3252a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  for (int i = 0; i < kPauseIterations; ++i) {
3262a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    RUN_ON_AUDIO_THREAD(StopSomeOutputStreams);
3272a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    WaitForDataToFlow();
3282a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    RUN_ON_AUDIO_THREAD(RestartAllStoppedOutputStreams);
3292a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    WaitForDataToFlow();
3302a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
3312a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  for (int i = 0; i < kHalfNumOutputs; ++i) {
3322a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    RUN_ON_AUDIO_THREAD(StopAndCloseOneOutputStream);
3332a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
3342a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  RUN_ON_AUDIO_THREAD(Stop);
3352a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  for (int i = 0; i < kHalfNumOutputs; ++i) {
3362a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    RUN_ON_AUDIO_THREAD(StopAndCloseOneOutputStream);
3372a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
3382a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  RUN_ON_AUDIO_THREAD(Close);
3392a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  WaitUntilClosed();
3402a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
3412a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
342eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen MurdochINSTANTIATE_TEST_CASE_P(SingleVersusMultithreaded,
343eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch                        VirtualAudioInputStreamTest,
344eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch                        ::testing::Values(false, true));
345eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
3462a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}  // namespace media
347