Updating trunk VERSION from 2139.0 to 2140.0
[chromium-blink-merge.git] / content / browser / media / capture / web_contents_audio_input_stream_unittest.cc
blob95592a854dc471f35a6504b6021a41bc52ae2a3a
1 // Copyright (c) 2013 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.
5 #include "content/browser/media/capture/web_contents_audio_input_stream.h"
7 #include <list>
9 #include "base/bind.h"
10 #include "base/bind_helpers.h"
11 #include "base/message_loop/message_loop.h"
12 #include "base/synchronization/waitable_event.h"
13 #include "base/threading/thread.h"
14 #include "content/browser/media/capture/audio_mirroring_manager.h"
15 #include "content/browser/media/capture/web_contents_tracker.h"
16 #include "content/public/browser/browser_thread.h"
17 #include "content/public/test/test_browser_thread_bundle.h"
18 #include "media/audio/simple_sources.h"
19 #include "media/audio/virtual_audio_input_stream.h"
20 #include "testing/gmock/include/gmock/gmock.h"
21 #include "testing/gtest/include/gtest/gtest.h"
23 using ::testing::_;
24 using ::testing::Assign;
25 using ::testing::DoAll;
26 using ::testing::Invoke;
27 using ::testing::InvokeWithoutArgs;
28 using ::testing::NotNull;
29 using ::testing::SaveArg;
30 using ::testing::WithArgs;
32 using media::AudioInputStream;
33 using media::AudioOutputStream;
34 using media::AudioParameters;
35 using media::SineWaveAudioSource;
36 using media::VirtualAudioInputStream;
37 using media::VirtualAudioOutputStream;
39 namespace content {
41 namespace {
43 const int kRenderProcessId = 123;
44 const int kRenderViewId = 456;
45 const int kAnotherRenderProcessId = 789;
46 const int kAnotherRenderViewId = 1;
48 const AudioParameters& TestAudioParameters() {
49 static const AudioParameters params(
50 AudioParameters::AUDIO_FAKE,
51 media::CHANNEL_LAYOUT_STEREO,
52 AudioParameters::kAudioCDSampleRate, 16,
53 AudioParameters::kAudioCDSampleRate / 100);
54 return params;
57 class MockAudioMirroringManager : public AudioMirroringManager {
58 public:
59 MockAudioMirroringManager() : AudioMirroringManager() {}
60 virtual ~MockAudioMirroringManager() {}
62 MOCK_METHOD3(StartMirroring,
63 void(int render_process_id, int render_view_id,
64 MirroringDestination* destination));
65 MOCK_METHOD3(StopMirroring,
66 void(int render_process_id, int render_view_id,
67 MirroringDestination* destination));
69 private:
70 DISALLOW_COPY_AND_ASSIGN(MockAudioMirroringManager);
73 class MockWebContentsTracker : public WebContentsTracker {
74 public:
75 MockWebContentsTracker() : WebContentsTracker() {}
77 MOCK_METHOD3(Start,
78 void(int render_process_id, int render_view_id,
79 const ChangeCallback& callback));
80 MOCK_METHOD0(Stop, void());
82 private:
83 virtual ~MockWebContentsTracker() {}
85 DISALLOW_COPY_AND_ASSIGN(MockWebContentsTracker);
88 // A fully-functional VirtualAudioInputStream, but methods are mocked to allow
89 // tests to check how/when they are invoked.
90 class MockVirtualAudioInputStream : public VirtualAudioInputStream {
91 public:
92 explicit MockVirtualAudioInputStream(
93 const scoped_refptr<base::MessageLoopProxy>& worker_loop)
94 : VirtualAudioInputStream(TestAudioParameters(), worker_loop,
95 VirtualAudioInputStream::AfterCloseCallback()),
96 real_(TestAudioParameters(), worker_loop,
97 base::Bind(&MockVirtualAudioInputStream::OnRealStreamHasClosed,
98 base::Unretained(this))),
99 real_stream_is_closed_(false) {
100 // Set default actions of mocked methods to delegate to the concrete
101 // implementation.
102 ON_CALL(*this, Open())
103 .WillByDefault(Invoke(&real_, &VirtualAudioInputStream::Open));
104 ON_CALL(*this, Start(_))
105 .WillByDefault(Invoke(&real_, &VirtualAudioInputStream::Start));
106 ON_CALL(*this, Stop())
107 .WillByDefault(Invoke(&real_, &VirtualAudioInputStream::Stop));
108 ON_CALL(*this, Close())
109 .WillByDefault(Invoke(&real_, &VirtualAudioInputStream::Close));
110 ON_CALL(*this, GetMaxVolume())
111 .WillByDefault(Invoke(&real_, &VirtualAudioInputStream::GetMaxVolume));
112 ON_CALL(*this, SetVolume(_))
113 .WillByDefault(Invoke(&real_, &VirtualAudioInputStream::SetVolume));
114 ON_CALL(*this, GetVolume())
115 .WillByDefault(Invoke(&real_, &VirtualAudioInputStream::GetVolume));
116 ON_CALL(*this, SetAutomaticGainControl(_))
117 .WillByDefault(
118 Invoke(&real_, &VirtualAudioInputStream::SetAutomaticGainControl));
119 ON_CALL(*this, GetAutomaticGainControl())
120 .WillByDefault(
121 Invoke(&real_, &VirtualAudioInputStream::GetAutomaticGainControl));
122 ON_CALL(*this, AddOutputStream(NotNull(), _))
123 .WillByDefault(
124 Invoke(&real_, &VirtualAudioInputStream::AddOutputStream));
125 ON_CALL(*this, RemoveOutputStream(NotNull(), _))
126 .WillByDefault(
127 Invoke(&real_, &VirtualAudioInputStream::RemoveOutputStream));
130 ~MockVirtualAudioInputStream() {
131 DCHECK(real_stream_is_closed_);
134 MOCK_METHOD0(Open, bool());
135 MOCK_METHOD1(Start, void(AudioInputStream::AudioInputCallback*));
136 MOCK_METHOD0(Stop, void());
137 MOCK_METHOD0(Close, void());
138 MOCK_METHOD0(GetMaxVolume, double());
139 MOCK_METHOD1(SetVolume, void(double));
140 MOCK_METHOD0(GetVolume, double());
141 MOCK_METHOD1(SetAutomaticGainControl, void(bool));
142 MOCK_METHOD0(GetAutomaticGainControl, bool());
143 MOCK_METHOD2(AddOutputStream, void(VirtualAudioOutputStream*,
144 const AudioParameters&));
145 MOCK_METHOD2(RemoveOutputStream, void(VirtualAudioOutputStream*,
146 const AudioParameters&));
148 private:
149 void OnRealStreamHasClosed(VirtualAudioInputStream* stream) {
150 DCHECK_EQ(&real_, stream);
151 DCHECK(!real_stream_is_closed_);
152 real_stream_is_closed_ = true;
155 VirtualAudioInputStream real_;
156 bool real_stream_is_closed_;
158 DISALLOW_COPY_AND_ASSIGN(MockVirtualAudioInputStream);
161 class MockAudioInputCallback : public AudioInputStream::AudioInputCallback {
162 public:
163 MockAudioInputCallback() {}
165 MOCK_METHOD4(OnData,
166 void(AudioInputStream* stream,
167 const media::AudioBus* src,
168 uint32 hardware_delay_bytes,
169 double volume));
170 MOCK_METHOD1(OnError, void(AudioInputStream* stream));
172 private:
173 DISALLOW_COPY_AND_ASSIGN(MockAudioInputCallback);
176 } // namespace
178 class WebContentsAudioInputStreamTest : public testing::Test {
179 public:
180 WebContentsAudioInputStreamTest()
181 : thread_bundle_(new TestBrowserThreadBundle(
182 TestBrowserThreadBundle::REAL_IO_THREAD)),
183 audio_thread_("Audio thread"),
184 mock_mirroring_manager_(new MockAudioMirroringManager()),
185 mock_tracker_(new MockWebContentsTracker()),
186 mock_vais_(NULL),
187 wcais_(NULL),
188 destination_(NULL),
189 current_render_process_id_(kRenderProcessId),
190 current_render_view_id_(kRenderViewId),
191 on_data_event_(false, false) {
192 audio_thread_.Start();
195 virtual ~WebContentsAudioInputStreamTest() {
196 audio_thread_.Stop();
197 thread_bundle_.reset();
199 DCHECK(!mock_vais_);
200 DCHECK(!wcais_);
201 EXPECT_FALSE(destination_);
202 DCHECK(streams_.empty());
203 DCHECK(sources_.empty());
206 void Open() {
207 mock_vais_ =
208 new MockVirtualAudioInputStream(audio_thread_.message_loop_proxy());
209 EXPECT_CALL(*mock_vais_, Open());
210 EXPECT_CALL(*mock_vais_, Close()); // At Close() time.
212 ASSERT_EQ(kRenderProcessId, current_render_process_id_);
213 ASSERT_EQ(kRenderViewId, current_render_view_id_);
214 EXPECT_CALL(*mock_tracker_.get(), Start(kRenderProcessId, kRenderViewId, _))
215 .WillOnce(DoAll(
216 SaveArg<2>(&change_callback_),
217 WithArgs<0, 1>(Invoke(&change_callback_,
218 &WebContentsTracker::ChangeCallback::Run))));
219 EXPECT_CALL(*mock_tracker_.get(), Stop()); // At Close() time.
221 wcais_ = new WebContentsAudioInputStream(
222 current_render_process_id_, current_render_view_id_,
223 mock_mirroring_manager_.get(),
224 mock_tracker_, mock_vais_);
225 wcais_->Open();
228 void Start() {
229 EXPECT_CALL(*mock_vais_, Start(&mock_input_callback_));
230 EXPECT_CALL(*mock_vais_, Stop()); // At Stop() time.
232 EXPECT_CALL(*mock_mirroring_manager_,
233 StartMirroring(kRenderProcessId, kRenderViewId, NotNull()))
234 .WillOnce(SaveArg<2>(&destination_))
235 .RetiresOnSaturation();
236 // At Stop() time, or when the mirroring target changes:
237 EXPECT_CALL(*mock_mirroring_manager_,
238 StopMirroring(kRenderProcessId, kRenderViewId, NotNull()))
239 .WillOnce(Assign(
240 &destination_,
241 static_cast<AudioMirroringManager::MirroringDestination*>(NULL)))
242 .RetiresOnSaturation();
244 EXPECT_CALL(mock_input_callback_, OnData(NotNull(), NotNull(), _, _))
245 .WillRepeatedly(
246 InvokeWithoutArgs(&on_data_event_, &base::WaitableEvent::Signal));
248 wcais_->Start(&mock_input_callback_);
250 // Test plumbing of volume controls and automatic gain controls. Calls to
251 // wcais_ methods should delegate directly to mock_vais_.
252 EXPECT_CALL(*mock_vais_, GetVolume());
253 double volume = wcais_->GetVolume();
254 EXPECT_CALL(*mock_vais_, GetMaxVolume());
255 const double max_volume = wcais_->GetMaxVolume();
256 volume *= 2.0;
257 if (volume < max_volume) {
258 volume = max_volume;
260 EXPECT_CALL(*mock_vais_, SetVolume(volume));
261 wcais_->SetVolume(volume);
262 EXPECT_CALL(*mock_vais_, GetAutomaticGainControl());
263 bool auto_gain = wcais_->GetAutomaticGainControl();
264 auto_gain = !auto_gain;
265 EXPECT_CALL(*mock_vais_, SetAutomaticGainControl(auto_gain));
266 wcais_->SetAutomaticGainControl(auto_gain);
269 void AddAnotherInput() {
270 // Note: WCAIS posts a task to invoke
271 // MockAudioMirroringManager::StartMirroring() on the IO thread, which
272 // causes our mock to set |destination_|. Block until that has happened.
273 base::WaitableEvent done(false, false);
274 BrowserThread::PostTask(
275 BrowserThread::IO, FROM_HERE, base::Bind(
276 &base::WaitableEvent::Signal, base::Unretained(&done)));
277 done.Wait();
278 ASSERT_TRUE(destination_);
280 EXPECT_CALL(*mock_vais_, AddOutputStream(NotNull(), _))
281 .RetiresOnSaturation();
282 // Later, when stream is closed:
283 EXPECT_CALL(*mock_vais_, RemoveOutputStream(NotNull(), _))
284 .RetiresOnSaturation();
286 const AudioParameters& params = TestAudioParameters();
287 AudioOutputStream* const out = destination_->AddInput(params);
288 ASSERT_TRUE(out);
289 streams_.push_back(out);
290 EXPECT_TRUE(out->Open());
291 SineWaveAudioSource* const source = new SineWaveAudioSource(
292 params.channel_layout(), 200.0, params.sample_rate());
293 sources_.push_back(source);
294 out->Start(source);
297 void RemoveOneInputInFIFOOrder() {
298 ASSERT_FALSE(streams_.empty());
299 AudioOutputStream* const out = streams_.front();
300 streams_.pop_front();
301 out->Stop();
302 out->Close(); // Self-deletes.
303 ASSERT_TRUE(!sources_.empty());
304 delete sources_.front();
305 sources_.pop_front();
308 void ChangeMirroringTarget() {
309 const int next_render_process_id =
310 current_render_process_id_ == kRenderProcessId ?
311 kAnotherRenderProcessId : kRenderProcessId;
312 const int next_render_view_id =
313 current_render_view_id_ == kRenderViewId ?
314 kAnotherRenderViewId : kRenderViewId;
316 EXPECT_CALL(*mock_mirroring_manager_,
317 StartMirroring(next_render_process_id, next_render_view_id,
318 NotNull()))
319 .WillOnce(SaveArg<2>(&destination_))
320 .RetiresOnSaturation();
321 // At Stop() time, or when the mirroring target changes:
322 EXPECT_CALL(*mock_mirroring_manager_,
323 StopMirroring(next_render_process_id, next_render_view_id,
324 NotNull()))
325 .WillOnce(Assign(
326 &destination_,
327 static_cast<AudioMirroringManager::MirroringDestination*>(NULL)))
328 .RetiresOnSaturation();
330 // Simulate OnTargetChange() callback from WebContentsTracker.
331 EXPECT_FALSE(change_callback_.is_null());
332 change_callback_.Run(next_render_process_id, next_render_view_id);
334 current_render_process_id_ = next_render_process_id;
335 current_render_view_id_ = next_render_view_id;
338 void LoseMirroringTarget() {
339 EXPECT_CALL(mock_input_callback_, OnError(_));
341 // Simulate OnTargetChange() callback from WebContentsTracker.
342 EXPECT_FALSE(change_callback_.is_null());
343 change_callback_.Run(-1, -1);
346 void Stop() {
347 wcais_->Stop();
350 void Close() {
351 // WebContentsAudioInputStream self-destructs on Close(). Its internal
352 // objects hang around until they are no longer referred to (e.g., as tasks
353 // on other threads shut things down).
354 wcais_->Close();
355 wcais_ = NULL;
356 mock_vais_ = NULL;
359 void RunOnAudioThread(const base::Closure& closure) {
360 audio_thread_.message_loop()->PostTask(FROM_HERE, closure);
363 // Block the calling thread until OnData() callbacks are being made.
364 void WaitForData() {
365 // Note: Arbitrarily chosen, but more iterations causes tests to take
366 // significantly more time.
367 static const int kNumIterations = 3;
368 for (int i = 0; i < kNumIterations; ++i)
369 on_data_event_.Wait();
372 private:
373 scoped_ptr<TestBrowserThreadBundle> thread_bundle_;
374 base::Thread audio_thread_;
376 scoped_ptr<MockAudioMirroringManager> mock_mirroring_manager_;
377 scoped_refptr<MockWebContentsTracker> mock_tracker_;
379 MockVirtualAudioInputStream* mock_vais_; // Owned by wcais_.
380 WebContentsAudioInputStream* wcais_; // Self-destructs on Close().
382 // Mock consumer of audio data.
383 MockAudioInputCallback mock_input_callback_;
385 // Provided by WebContentsAudioInputStream to the mock WebContentsTracker.
386 // This callback is saved here, and test code will invoke it to simulate
387 // target change events.
388 WebContentsTracker::ChangeCallback change_callback_;
390 // Provided by WebContentsAudioInputStream to the mock AudioMirroringManager.
391 // A pointer to the implementation is saved here, and test code will invoke it
392 // to simulate: 1) calls to AddInput(); and 2) diverting audio data.
393 AudioMirroringManager::MirroringDestination* destination_;
395 // Current target RenderView. These get flipped in ChangedMirroringTarget().
396 int current_render_process_id_;
397 int current_render_view_id_;
399 // Streams provided by calls to WebContentsAudioInputStream::AddInput(). Each
400 // is started with a simulated source of audio data.
401 std::list<AudioOutputStream*> streams_;
402 std::list<SineWaveAudioSource*> sources_; // 1:1 with elements in streams_.
404 base::WaitableEvent on_data_event_;
406 DISALLOW_COPY_AND_ASSIGN(WebContentsAudioInputStreamTest);
409 #define RUN_ON_AUDIO_THREAD(method) \
410 RunOnAudioThread(base::Bind(&WebContentsAudioInputStreamTest::method, \
411 base::Unretained(this)))
413 TEST_F(WebContentsAudioInputStreamTest, OpenedButNeverStarted) {
414 RUN_ON_AUDIO_THREAD(Open);
415 RUN_ON_AUDIO_THREAD(Close);
418 TEST_F(WebContentsAudioInputStreamTest, MirroringNothing) {
419 RUN_ON_AUDIO_THREAD(Open);
420 RUN_ON_AUDIO_THREAD(Start);
421 WaitForData();
422 RUN_ON_AUDIO_THREAD(Stop);
423 RUN_ON_AUDIO_THREAD(Close);
426 TEST_F(WebContentsAudioInputStreamTest, MirroringOutputOutlivesSession) {
427 RUN_ON_AUDIO_THREAD(Open);
428 RUN_ON_AUDIO_THREAD(Start);
429 RUN_ON_AUDIO_THREAD(AddAnotherInput);
430 WaitForData();
431 RUN_ON_AUDIO_THREAD(Stop);
432 RUN_ON_AUDIO_THREAD(Close);
433 RUN_ON_AUDIO_THREAD(RemoveOneInputInFIFOOrder);
436 TEST_F(WebContentsAudioInputStreamTest, MirroringOutputWithinSession) {
437 RUN_ON_AUDIO_THREAD(Open);
438 RUN_ON_AUDIO_THREAD(Start);
439 RUN_ON_AUDIO_THREAD(AddAnotherInput);
440 WaitForData();
441 RUN_ON_AUDIO_THREAD(RemoveOneInputInFIFOOrder);
442 RUN_ON_AUDIO_THREAD(Stop);
443 RUN_ON_AUDIO_THREAD(Close);
446 TEST_F(WebContentsAudioInputStreamTest, MirroringNothingWithTargetChange) {
447 RUN_ON_AUDIO_THREAD(Open);
448 RUN_ON_AUDIO_THREAD(Start);
449 RUN_ON_AUDIO_THREAD(ChangeMirroringTarget);
450 RUN_ON_AUDIO_THREAD(Stop);
451 RUN_ON_AUDIO_THREAD(Close);
454 TEST_F(WebContentsAudioInputStreamTest, MirroringOneStreamAfterTargetChange) {
455 RUN_ON_AUDIO_THREAD(Open);
456 RUN_ON_AUDIO_THREAD(Start);
457 RUN_ON_AUDIO_THREAD(ChangeMirroringTarget);
458 RUN_ON_AUDIO_THREAD(AddAnotherInput);
459 WaitForData();
460 RUN_ON_AUDIO_THREAD(Stop);
461 RUN_ON_AUDIO_THREAD(Close);
462 RUN_ON_AUDIO_THREAD(RemoveOneInputInFIFOOrder);
465 TEST_F(WebContentsAudioInputStreamTest, MirroringOneStreamWithTargetChange) {
466 RUN_ON_AUDIO_THREAD(Open);
467 RUN_ON_AUDIO_THREAD(Start);
468 RUN_ON_AUDIO_THREAD(AddAnotherInput);
469 WaitForData();
470 RUN_ON_AUDIO_THREAD(ChangeMirroringTarget);
471 RUN_ON_AUDIO_THREAD(RemoveOneInputInFIFOOrder);
472 RUN_ON_AUDIO_THREAD(AddAnotherInput);
473 WaitForData();
474 RUN_ON_AUDIO_THREAD(Stop);
475 RUN_ON_AUDIO_THREAD(Close);
476 RUN_ON_AUDIO_THREAD(RemoveOneInputInFIFOOrder);
479 TEST_F(WebContentsAudioInputStreamTest, MirroringLostTarget) {
480 RUN_ON_AUDIO_THREAD(Open);
481 RUN_ON_AUDIO_THREAD(Start);
482 RUN_ON_AUDIO_THREAD(AddAnotherInput);
483 WaitForData();
484 RUN_ON_AUDIO_THREAD(LoseMirroringTarget);
485 RUN_ON_AUDIO_THREAD(RemoveOneInputInFIFOOrder);
486 RUN_ON_AUDIO_THREAD(Stop);
487 RUN_ON_AUDIO_THREAD(Close);
490 TEST_F(WebContentsAudioInputStreamTest, MirroringMultipleStreamsAndTargets) {
491 RUN_ON_AUDIO_THREAD(Open);
492 RUN_ON_AUDIO_THREAD(Start);
493 RUN_ON_AUDIO_THREAD(AddAnotherInput);
494 WaitForData();
495 RUN_ON_AUDIO_THREAD(AddAnotherInput);
496 RUN_ON_AUDIO_THREAD(AddAnotherInput);
497 RUN_ON_AUDIO_THREAD(AddAnotherInput);
498 WaitForData();
499 RUN_ON_AUDIO_THREAD(ChangeMirroringTarget);
500 RUN_ON_AUDIO_THREAD(RemoveOneInputInFIFOOrder);
501 WaitForData();
502 RUN_ON_AUDIO_THREAD(RemoveOneInputInFIFOOrder);
503 RUN_ON_AUDIO_THREAD(RemoveOneInputInFIFOOrder);
504 RUN_ON_AUDIO_THREAD(AddAnotherInput);
505 WaitForData();
506 RUN_ON_AUDIO_THREAD(RemoveOneInputInFIFOOrder);
507 WaitForData();
508 RUN_ON_AUDIO_THREAD(ChangeMirroringTarget);
509 RUN_ON_AUDIO_THREAD(RemoveOneInputInFIFOOrder);
510 RUN_ON_AUDIO_THREAD(Stop);
511 RUN_ON_AUDIO_THREAD(Close);
514 } // namespace content