virtual_audio_input_stream_unittest.cc revision 2a99a7e74a7f215066514fe81d2bfa6639d9eddd
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/message_loop.h"
102a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "base/rand_util.h"
112a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "base/synchronization/waitable_event.h"
122a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "base/threading/thread.h"
132a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "media/audio/audio_io.h"
142a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "media/audio/simple_sources.h"
152a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "media/audio/virtual_audio_input_stream.h"
162a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "media/audio/virtual_audio_output_stream.h"
172a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "testing/gmock/include/gmock/gmock.h"
182a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "testing/gtest/include/gtest/gtest.h"
192a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
202a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)using ::testing::_;
212a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)using ::testing::AtLeast;
222a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)using ::testing::InvokeWithoutArgs;
232a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)using ::testing::NotNull;
242a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
252a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)namespace media {
262a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
272a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)namespace {
282a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
292a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)const AudioParameters kParams(
302a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    AudioParameters::AUDIO_PCM_LOW_LATENCY, CHANNEL_LAYOUT_STEREO, 8000, 8, 10);
312a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
322a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)class MockInputCallback : public AudioInputStream::AudioInputCallback {
332a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) public:
342a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  MockInputCallback()
352a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      : data_pushed_(false, false) {
362a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    ON_CALL(*this, OnData(_, _, _, _, _))
372a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        .WillByDefault(InvokeWithoutArgs(&data_pushed_,
382a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                                         &base::WaitableEvent::Signal));
392a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
402a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
412a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  virtual ~MockInputCallback() {}
422a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
432a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  MOCK_METHOD5(OnData, void(AudioInputStream* stream, const uint8* data,
442a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                            uint32 size, uint32 hardware_delay_bytes,
452a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                            double volume));
462a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  MOCK_METHOD1(OnClose, void(AudioInputStream* stream));
472a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  MOCK_METHOD1(OnError, void(AudioInputStream* stream));
482a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
492a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  void WaitForDataPushes() {
502a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    for (int i = 0; i < 3; ++i) {
512a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      data_pushed_.Wait();
522a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    }
532a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
542a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
552a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) private:
562a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  base::WaitableEvent data_pushed_;
572a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
582a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  DISALLOW_COPY_AND_ASSIGN(MockInputCallback);
592a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)};
602a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
612a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)class TestAudioSource : public SineWaveAudioSource {
622a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) public:
632a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  TestAudioSource()
642a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      : SineWaveAudioSource(
652a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)            kParams.channel_layout(), 200.0, kParams.sample_rate()),
662a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        data_pulled_(false, false) {}
672a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
682a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  virtual ~TestAudioSource() {}
692a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
702a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  virtual int OnMoreData(AudioBus* audio_bus,
712a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                         AudioBuffersState audio_buffers) OVERRIDE {
722a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    const int ret = SineWaveAudioSource::OnMoreData(audio_bus, audio_buffers);
732a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    data_pulled_.Signal();
742a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return ret;
752a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
762a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
772a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  virtual int OnMoreIOData(AudioBus* source,
782a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                           AudioBus* dest,
792a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                           AudioBuffersState audio_buffers) OVERRIDE {
802a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    const int ret =
812a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        SineWaveAudioSource::OnMoreIOData(source, dest, audio_buffers);
822a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    data_pulled_.Signal();
832a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return ret;
842a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
852a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
862a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  void WaitForDataPulls() {
872a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    for (int i = 0; i < 3; ++i) {
882a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      data_pulled_.Wait();
892a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    }
902a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
912a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
922a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) private:
932a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  base::WaitableEvent data_pulled_;
942a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
952a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  DISALLOW_COPY_AND_ASSIGN(TestAudioSource);
962a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)};
972a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
982a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}  // namespace
992a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1002a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)class VirtualAudioInputStreamTest : public testing::Test {
1012a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) public:
1022a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  VirtualAudioInputStreamTest()
1032a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      : audio_thread_(new base::Thread("AudioThread")),
1042a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        stream_(NULL),
1052a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        closed_stream_(false, false) {
1062a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    audio_thread_->Start();
1072a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    audio_message_loop_ = audio_thread_->message_loop_proxy();
1082a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
1092a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1102a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  virtual ~VirtualAudioInputStreamTest() {
1112a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    SyncWithAudioThread();
1122a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1132a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    DCHECK(output_streams_.empty());
1142a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    DCHECK(stopped_output_streams_.empty());
1152a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
1162a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1172a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  void Create() {
1182a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    stream_ = new VirtualAudioInputStream(
1192a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        kParams, audio_message_loop_,
1202a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        base::Bind(&base::DeletePointer<VirtualAudioInputStream>));
1212a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    stream_->Open();
1222a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
1232a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1242a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  void Start() {
1252a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    EXPECT_CALL(input_callback_, OnClose(_));
1262a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    EXPECT_CALL(input_callback_, OnData(_, NotNull(), _, _, _))
1272a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        .Times(AtLeast(1));
1282a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1292a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    ASSERT_TRUE(!!stream_);
1302a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    stream_->Start(&input_callback_);
1312a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
1322a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1332a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  void CreateAndStartOneOutputStream() {
1342a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    ASSERT_TRUE(!!stream_);
1352a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    AudioOutputStream* const output_stream =
1362a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        new VirtualAudioOutputStream(
1372a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)            kParams, audio_message_loop_, stream_,
1382a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)            base::Bind(&base::DeletePointer<VirtualAudioOutputStream>));
1392a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    output_streams_.push_back(output_stream);
1402a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1412a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    output_stream->Open();
1422a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    output_stream->Start(&source_);
1432a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
1442a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1452a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  void Stop() {
1462a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    ASSERT_TRUE(!!stream_);
1472a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    stream_->Stop();
1482a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
1492a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1502a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  void Close() {
1512a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    ASSERT_TRUE(!!stream_);
1522a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    stream_->Close();
1532a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    stream_ = NULL;
1542a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    closed_stream_.Signal();
1552a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
1562a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1572a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  void WaitForDataToFlow() {
1582a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    // Wait until audio thread is idle before calling output_streams_.size().
1592a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    SyncWithAudioThread();
1602a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1612a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    const int count = output_streams_.size();
1622a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    for (int i = 0; i < count; ++i) {
1632a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      source_.WaitForDataPulls();
1642a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    }
1652a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1662a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    input_callback_.WaitForDataPushes();
1672a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
1682a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1692a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  void WaitUntilClosed() {
1702a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    closed_stream_.Wait();
1712a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
1722a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1732a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  void StopAndCloseOneOutputStream() {
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)
1792a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    output_stream->Stop();
1802a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    output_stream->Close();
1812a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
1822a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1832a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  void StopFirstOutputStream() {
1842a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    ASSERT_TRUE(!output_streams_.empty());
1852a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    AudioOutputStream* const output_stream = output_streams_.front();
1862a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    ASSERT_TRUE(!!output_stream);
1872a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    output_streams_.pop_front();
1882a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    output_stream->Stop();
1892a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    stopped_output_streams_.push_back(output_stream);
1902a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
1912a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1922a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  void StopSomeOutputStreams() {
1932a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    ASSERT_LE(2, static_cast<int>(output_streams_.size()));
1942a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    for (int remaning = base::RandInt(1, output_streams_.size() - 1);
1952a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)         remaning > 0; --remaning) {
1962a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      StopFirstOutputStream();
1972a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    }
1982a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
1992a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
2002a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  void RestartAllStoppedOutputStreams() {
2012a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    typedef std::list<AudioOutputStream*>::const_iterator ConstIter;
2022a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    for (ConstIter it = stopped_output_streams_.begin();
2032a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)         it != stopped_output_streams_.end(); ++it) {
2042a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      (*it)->Start(&source_);
2052a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      output_streams_.push_back(*it);
2062a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    }
2072a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    stopped_output_streams_.clear();
2082a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
2092a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
2102a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  const scoped_refptr<base::MessageLoopProxy>& audio_message_loop() const {
2112a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return audio_message_loop_;
2122a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
2132a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
2142a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) private:
2152a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  void SyncWithAudioThread() {
2162a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    base::WaitableEvent done(false, false);
2172a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    audio_message_loop_->PostTask(
2182a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        FROM_HERE,
2192a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        base::Bind(&base::WaitableEvent::Signal, base::Unretained(&done)));
2202a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    done.Wait();
2212a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
2222a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
2232a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  scoped_ptr<base::Thread> audio_thread_;
2242a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  scoped_refptr<base::MessageLoopProxy> audio_message_loop_;
2252a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
2262a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  VirtualAudioInputStream* stream_;
2272a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  MockInputCallback input_callback_;
2282a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  base::WaitableEvent closed_stream_;
2292a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
2302a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  std::list<AudioOutputStream*> output_streams_;
2312a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  std::list<AudioOutputStream*> stopped_output_streams_;
2322a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  TestAudioSource source_;
2332a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
2342a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  DISALLOW_COPY_AND_ASSIGN(VirtualAudioInputStreamTest);
2352a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)};
2362a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
2372a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#define RUN_ON_AUDIO_THREAD(method)  \
2382a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  audio_message_loop()->PostTask(  \
2392a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      FROM_HERE, base::Bind(&VirtualAudioInputStreamTest::method,  \
2402a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                            base::Unretained(this)))
2412a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
2422a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)TEST_F(VirtualAudioInputStreamTest, CreateAndClose) {
2432a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  RUN_ON_AUDIO_THREAD(Create);
2442a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  RUN_ON_AUDIO_THREAD(Close);
2452a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  WaitUntilClosed();
2462a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
2472a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
2482a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)TEST_F(VirtualAudioInputStreamTest, NoOutputs) {
2492a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  RUN_ON_AUDIO_THREAD(Create);
2502a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  RUN_ON_AUDIO_THREAD(Start);
2512a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  WaitForDataToFlow();
2522a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  RUN_ON_AUDIO_THREAD(Stop);
2532a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  RUN_ON_AUDIO_THREAD(Close);
2542a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  WaitUntilClosed();
2552a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
2562a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
2572a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)TEST_F(VirtualAudioInputStreamTest, SingleOutput) {
2582a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  RUN_ON_AUDIO_THREAD(Create);
2592a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  RUN_ON_AUDIO_THREAD(Start);
2602a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  RUN_ON_AUDIO_THREAD(CreateAndStartOneOutputStream);
2612a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  WaitForDataToFlow();
2622a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  RUN_ON_AUDIO_THREAD(StopAndCloseOneOutputStream);
2632a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  RUN_ON_AUDIO_THREAD(Stop);
2642a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  RUN_ON_AUDIO_THREAD(Close);
2652a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  WaitUntilClosed();
2662a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
2672a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
2682a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)TEST_F(VirtualAudioInputStreamTest, SingleOutputPausedAndRestarted) {
2692a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  RUN_ON_AUDIO_THREAD(Create);
2702a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  RUN_ON_AUDIO_THREAD(Start);
2712a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  RUN_ON_AUDIO_THREAD(CreateAndStartOneOutputStream);
2722a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  WaitForDataToFlow();
2732a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  RUN_ON_AUDIO_THREAD(StopFirstOutputStream);
2742a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  RUN_ON_AUDIO_THREAD(RestartAllStoppedOutputStreams);
2752a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  WaitForDataToFlow();
2762a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  RUN_ON_AUDIO_THREAD(StopAndCloseOneOutputStream);
2772a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  RUN_ON_AUDIO_THREAD(Stop);
2782a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  RUN_ON_AUDIO_THREAD(Close);
2792a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  WaitUntilClosed();
2802a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
2812a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
2822a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)TEST_F(VirtualAudioInputStreamTest, MultipleOutputs) {
2832a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  RUN_ON_AUDIO_THREAD(Create);
2842a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  RUN_ON_AUDIO_THREAD(Start);
2852a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  RUN_ON_AUDIO_THREAD(CreateAndStartOneOutputStream);
2862a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  WaitForDataToFlow();
2872a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  RUN_ON_AUDIO_THREAD(CreateAndStartOneOutputStream);
2882a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  RUN_ON_AUDIO_THREAD(CreateAndStartOneOutputStream);
2892a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  WaitForDataToFlow();
2902a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  RUN_ON_AUDIO_THREAD(StopFirstOutputStream);
2912a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  RUN_ON_AUDIO_THREAD(StopFirstOutputStream);
2922a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  WaitForDataToFlow();
2932a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  RUN_ON_AUDIO_THREAD(StopFirstOutputStream);
2942a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  RUN_ON_AUDIO_THREAD(RestartAllStoppedOutputStreams);
2952a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  WaitForDataToFlow();
2962a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  RUN_ON_AUDIO_THREAD(StopAndCloseOneOutputStream);
2972a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  RUN_ON_AUDIO_THREAD(StopAndCloseOneOutputStream);
2982a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  RUN_ON_AUDIO_THREAD(Stop);
2992a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  RUN_ON_AUDIO_THREAD(StopAndCloseOneOutputStream);
3002a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  RUN_ON_AUDIO_THREAD(Close);
3012a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  WaitUntilClosed();
3022a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
3032a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
3042a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// A combination of all of the above tests with many output streams.
3052a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)TEST_F(VirtualAudioInputStreamTest, ComprehensiveTest) {
3062a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  static const int kNumOutputs = 8;
3072a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  static const int kHalfNumOutputs = kNumOutputs / 2;
3082a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  static const int kPauseIterations = 5;
3092a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
3102a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  RUN_ON_AUDIO_THREAD(Create);
3112a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  for (int i = 0; i < kHalfNumOutputs; ++i) {
3122a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    RUN_ON_AUDIO_THREAD(CreateAndStartOneOutputStream);
3132a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
3142a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  RUN_ON_AUDIO_THREAD(Start);
3152a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  WaitForDataToFlow();
3162a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  for (int i = 0; i < kHalfNumOutputs; ++i) {
3172a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    RUN_ON_AUDIO_THREAD(CreateAndStartOneOutputStream);
3182a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
3192a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  WaitForDataToFlow();
3202a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  for (int i = 0; i < kPauseIterations; ++i) {
3212a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    RUN_ON_AUDIO_THREAD(StopSomeOutputStreams);
3222a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    WaitForDataToFlow();
3232a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    RUN_ON_AUDIO_THREAD(RestartAllStoppedOutputStreams);
3242a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    WaitForDataToFlow();
3252a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
3262a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  for (int i = 0; i < kHalfNumOutputs; ++i) {
3272a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    RUN_ON_AUDIO_THREAD(StopAndCloseOneOutputStream);
3282a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
3292a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  RUN_ON_AUDIO_THREAD(Stop);
3302a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  for (int i = 0; i < kHalfNumOutputs; ++i) {
3312a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    RUN_ON_AUDIO_THREAD(StopAndCloseOneOutputStream);
3322a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
3332a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  RUN_ON_AUDIO_THREAD(Close);
3342a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  WaitUntilClosed();
3352a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
3362a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
3372a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}  // namespace media
338