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