virtual_audio_input_stream_unittest.cc revision 2a99a7e74a7f215066514fe81d2bfa6639d9eddd
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.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 20using ::testing::_; 21using ::testing::AtLeast; 22using ::testing::InvokeWithoutArgs; 23using ::testing::NotNull; 24 25namespace media { 26 27namespace { 28 29const AudioParameters kParams( 30 AudioParameters::AUDIO_PCM_LOW_LATENCY, CHANNEL_LAYOUT_STEREO, 8000, 8, 10); 31 32class 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 61class 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 100class VirtualAudioInputStreamTest : public testing::Test { 101 public: 102 VirtualAudioInputStreamTest() 103 : audio_thread_(new base::Thread("AudioThread")), 104 stream_(NULL), 105 closed_stream_(false, false) { 106 audio_thread_->Start(); 107 audio_message_loop_ = audio_thread_->message_loop_proxy(); 108 } 109 110 virtual ~VirtualAudioInputStreamTest() { 111 SyncWithAudioThread(); 112 113 DCHECK(output_streams_.empty()); 114 DCHECK(stopped_output_streams_.empty()); 115 } 116 117 void Create() { 118 stream_ = new VirtualAudioInputStream( 119 kParams, audio_message_loop_, 120 base::Bind(&base::DeletePointer<VirtualAudioInputStream>)); 121 stream_->Open(); 122 } 123 124 void Start() { 125 EXPECT_CALL(input_callback_, OnClose(_)); 126 EXPECT_CALL(input_callback_, OnData(_, NotNull(), _, _, _)) 127 .Times(AtLeast(1)); 128 129 ASSERT_TRUE(!!stream_); 130 stream_->Start(&input_callback_); 131 } 132 133 void CreateAndStartOneOutputStream() { 134 ASSERT_TRUE(!!stream_); 135 AudioOutputStream* const output_stream = 136 new VirtualAudioOutputStream( 137 kParams, audio_message_loop_, stream_, 138 base::Bind(&base::DeletePointer<VirtualAudioOutputStream>)); 139 output_streams_.push_back(output_stream); 140 141 output_stream->Open(); 142 output_stream->Start(&source_); 143 } 144 145 void Stop() { 146 ASSERT_TRUE(!!stream_); 147 stream_->Stop(); 148 } 149 150 void Close() { 151 ASSERT_TRUE(!!stream_); 152 stream_->Close(); 153 stream_ = NULL; 154 closed_stream_.Signal(); 155 } 156 157 void WaitForDataToFlow() { 158 // Wait until audio thread is idle before calling output_streams_.size(). 159 SyncWithAudioThread(); 160 161 const int count = output_streams_.size(); 162 for (int i = 0; i < count; ++i) { 163 source_.WaitForDataPulls(); 164 } 165 166 input_callback_.WaitForDataPushes(); 167 } 168 169 void WaitUntilClosed() { 170 closed_stream_.Wait(); 171 } 172 173 void StopAndCloseOneOutputStream() { 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 179 output_stream->Stop(); 180 output_stream->Close(); 181 } 182 183 void StopFirstOutputStream() { 184 ASSERT_TRUE(!output_streams_.empty()); 185 AudioOutputStream* const output_stream = output_streams_.front(); 186 ASSERT_TRUE(!!output_stream); 187 output_streams_.pop_front(); 188 output_stream->Stop(); 189 stopped_output_streams_.push_back(output_stream); 190 } 191 192 void StopSomeOutputStreams() { 193 ASSERT_LE(2, static_cast<int>(output_streams_.size())); 194 for (int remaning = base::RandInt(1, output_streams_.size() - 1); 195 remaning > 0; --remaning) { 196 StopFirstOutputStream(); 197 } 198 } 199 200 void RestartAllStoppedOutputStreams() { 201 typedef std::list<AudioOutputStream*>::const_iterator ConstIter; 202 for (ConstIter it = stopped_output_streams_.begin(); 203 it != stopped_output_streams_.end(); ++it) { 204 (*it)->Start(&source_); 205 output_streams_.push_back(*it); 206 } 207 stopped_output_streams_.clear(); 208 } 209 210 const scoped_refptr<base::MessageLoopProxy>& audio_message_loop() const { 211 return audio_message_loop_; 212 } 213 214 private: 215 void SyncWithAudioThread() { 216 base::WaitableEvent done(false, false); 217 audio_message_loop_->PostTask( 218 FROM_HERE, 219 base::Bind(&base::WaitableEvent::Signal, base::Unretained(&done))); 220 done.Wait(); 221 } 222 223 scoped_ptr<base::Thread> audio_thread_; 224 scoped_refptr<base::MessageLoopProxy> audio_message_loop_; 225 226 VirtualAudioInputStream* stream_; 227 MockInputCallback input_callback_; 228 base::WaitableEvent closed_stream_; 229 230 std::list<AudioOutputStream*> output_streams_; 231 std::list<AudioOutputStream*> stopped_output_streams_; 232 TestAudioSource source_; 233 234 DISALLOW_COPY_AND_ASSIGN(VirtualAudioInputStreamTest); 235}; 236 237#define RUN_ON_AUDIO_THREAD(method) \ 238 audio_message_loop()->PostTask( \ 239 FROM_HERE, base::Bind(&VirtualAudioInputStreamTest::method, \ 240 base::Unretained(this))) 241 242TEST_F(VirtualAudioInputStreamTest, CreateAndClose) { 243 RUN_ON_AUDIO_THREAD(Create); 244 RUN_ON_AUDIO_THREAD(Close); 245 WaitUntilClosed(); 246} 247 248TEST_F(VirtualAudioInputStreamTest, NoOutputs) { 249 RUN_ON_AUDIO_THREAD(Create); 250 RUN_ON_AUDIO_THREAD(Start); 251 WaitForDataToFlow(); 252 RUN_ON_AUDIO_THREAD(Stop); 253 RUN_ON_AUDIO_THREAD(Close); 254 WaitUntilClosed(); 255} 256 257TEST_F(VirtualAudioInputStreamTest, SingleOutput) { 258 RUN_ON_AUDIO_THREAD(Create); 259 RUN_ON_AUDIO_THREAD(Start); 260 RUN_ON_AUDIO_THREAD(CreateAndStartOneOutputStream); 261 WaitForDataToFlow(); 262 RUN_ON_AUDIO_THREAD(StopAndCloseOneOutputStream); 263 RUN_ON_AUDIO_THREAD(Stop); 264 RUN_ON_AUDIO_THREAD(Close); 265 WaitUntilClosed(); 266} 267 268TEST_F(VirtualAudioInputStreamTest, SingleOutputPausedAndRestarted) { 269 RUN_ON_AUDIO_THREAD(Create); 270 RUN_ON_AUDIO_THREAD(Start); 271 RUN_ON_AUDIO_THREAD(CreateAndStartOneOutputStream); 272 WaitForDataToFlow(); 273 RUN_ON_AUDIO_THREAD(StopFirstOutputStream); 274 RUN_ON_AUDIO_THREAD(RestartAllStoppedOutputStreams); 275 WaitForDataToFlow(); 276 RUN_ON_AUDIO_THREAD(StopAndCloseOneOutputStream); 277 RUN_ON_AUDIO_THREAD(Stop); 278 RUN_ON_AUDIO_THREAD(Close); 279 WaitUntilClosed(); 280} 281 282TEST_F(VirtualAudioInputStreamTest, MultipleOutputs) { 283 RUN_ON_AUDIO_THREAD(Create); 284 RUN_ON_AUDIO_THREAD(Start); 285 RUN_ON_AUDIO_THREAD(CreateAndStartOneOutputStream); 286 WaitForDataToFlow(); 287 RUN_ON_AUDIO_THREAD(CreateAndStartOneOutputStream); 288 RUN_ON_AUDIO_THREAD(CreateAndStartOneOutputStream); 289 WaitForDataToFlow(); 290 RUN_ON_AUDIO_THREAD(StopFirstOutputStream); 291 RUN_ON_AUDIO_THREAD(StopFirstOutputStream); 292 WaitForDataToFlow(); 293 RUN_ON_AUDIO_THREAD(StopFirstOutputStream); 294 RUN_ON_AUDIO_THREAD(RestartAllStoppedOutputStreams); 295 WaitForDataToFlow(); 296 RUN_ON_AUDIO_THREAD(StopAndCloseOneOutputStream); 297 RUN_ON_AUDIO_THREAD(StopAndCloseOneOutputStream); 298 RUN_ON_AUDIO_THREAD(Stop); 299 RUN_ON_AUDIO_THREAD(StopAndCloseOneOutputStream); 300 RUN_ON_AUDIO_THREAD(Close); 301 WaitUntilClosed(); 302} 303 304// A combination of all of the above tests with many output streams. 305TEST_F(VirtualAudioInputStreamTest, ComprehensiveTest) { 306 static const int kNumOutputs = 8; 307 static const int kHalfNumOutputs = kNumOutputs / 2; 308 static const int kPauseIterations = 5; 309 310 RUN_ON_AUDIO_THREAD(Create); 311 for (int i = 0; i < kHalfNumOutputs; ++i) { 312 RUN_ON_AUDIO_THREAD(CreateAndStartOneOutputStream); 313 } 314 RUN_ON_AUDIO_THREAD(Start); 315 WaitForDataToFlow(); 316 for (int i = 0; i < kHalfNumOutputs; ++i) { 317 RUN_ON_AUDIO_THREAD(CreateAndStartOneOutputStream); 318 } 319 WaitForDataToFlow(); 320 for (int i = 0; i < kPauseIterations; ++i) { 321 RUN_ON_AUDIO_THREAD(StopSomeOutputStreams); 322 WaitForDataToFlow(); 323 RUN_ON_AUDIO_THREAD(RestartAllStoppedOutputStreams); 324 WaitForDataToFlow(); 325 } 326 for (int i = 0; i < kHalfNumOutputs; ++i) { 327 RUN_ON_AUDIO_THREAD(StopAndCloseOneOutputStream); 328 } 329 RUN_ON_AUDIO_THREAD(Stop); 330 for (int i = 0; i < kHalfNumOutputs; ++i) { 331 RUN_ON_AUDIO_THREAD(StopAndCloseOneOutputStream); 332 } 333 RUN_ON_AUDIO_THREAD(Close); 334 WaitUntilClosed(); 335} 336 337} // namespace media 338