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