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