OLD | NEW |
1 // Copyright (c) 2013 The Chromium Authors. All rights reserved. | 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 | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "content/browser/media/capture/web_contents_audio_input_stream.h" | 5 #include "content/browser/media/capture/web_contents_audio_input_stream.h" |
6 | 6 |
7 #include <list> | 7 #include <list> |
8 | 8 |
9 #include "base/bind.h" | 9 #include "base/bind.h" |
10 #include "base/bind_helpers.h" | 10 #include "base/bind_helpers.h" |
(...skipping 23 matching lines...) Expand all Loading... |
34 using media::AudioParameters; | 34 using media::AudioParameters; |
35 using media::SineWaveAudioSource; | 35 using media::SineWaveAudioSource; |
36 using media::VirtualAudioInputStream; | 36 using media::VirtualAudioInputStream; |
37 using media::VirtualAudioOutputStream; | 37 using media::VirtualAudioOutputStream; |
38 | 38 |
39 namespace content { | 39 namespace content { |
40 | 40 |
41 namespace { | 41 namespace { |
42 | 42 |
43 const int kRenderProcessId = 123; | 43 const int kRenderProcessId = 123; |
44 const int kRenderViewId = 456; | 44 const int kRenderFrameId = 456; |
45 const int kAnotherRenderProcessId = 789; | 45 const int kAnotherRenderProcessId = 789; |
46 const int kAnotherRenderViewId = 1; | 46 const int kAnotherRenderFrameId = 1; |
47 | 47 |
48 const AudioParameters& TestAudioParameters() { | 48 const AudioParameters& TestAudioParameters() { |
49 static const AudioParameters params( | 49 static const AudioParameters params( |
50 AudioParameters::AUDIO_FAKE, | 50 AudioParameters::AUDIO_FAKE, |
51 media::CHANNEL_LAYOUT_STEREO, | 51 media::CHANNEL_LAYOUT_STEREO, |
52 AudioParameters::kAudioCDSampleRate, 16, | 52 AudioParameters::kAudioCDSampleRate, 16, |
53 AudioParameters::kAudioCDSampleRate / 100); | 53 AudioParameters::kAudioCDSampleRate / 100); |
54 return params; | 54 return params; |
55 } | 55 } |
56 | 56 |
57 class MockAudioMirroringManager : public AudioMirroringManager { | 57 class MockAudioMirroringManager : public AudioMirroringManager { |
58 public: | 58 public: |
59 MockAudioMirroringManager() : AudioMirroringManager() {} | 59 MockAudioMirroringManager() : AudioMirroringManager() {} |
60 virtual ~MockAudioMirroringManager() {} | 60 virtual ~MockAudioMirroringManager() {} |
61 | 61 |
62 MOCK_METHOD3(StartMirroring, | 62 MOCK_METHOD1(StartMirroring, void(MirroringDestination* destination)); |
63 void(int render_process_id, int render_view_id, | 63 MOCK_METHOD1(StopMirroring, void(MirroringDestination* destination)); |
64 MirroringDestination* destination)); | |
65 MOCK_METHOD3(StopMirroring, | |
66 void(int render_process_id, int render_view_id, | |
67 MirroringDestination* destination)); | |
68 | 64 |
69 private: | 65 private: |
70 DISALLOW_COPY_AND_ASSIGN(MockAudioMirroringManager); | 66 DISALLOW_COPY_AND_ASSIGN(MockAudioMirroringManager); |
71 }; | 67 }; |
72 | 68 |
73 class MockWebContentsTracker : public WebContentsTracker { | 69 class MockWebContentsTracker : public WebContentsTracker { |
74 public: | 70 public: |
75 MockWebContentsTracker() : WebContentsTracker() {} | 71 MockWebContentsTracker() : WebContentsTracker(false) {} |
76 | 72 |
77 MOCK_METHOD3(Start, | 73 MOCK_METHOD3(Start, |
78 void(int render_process_id, int render_view_id, | 74 void(int render_process_id, int render_frame_id, |
79 const ChangeCallback& callback)); | 75 const ChangeCallback& callback)); |
80 MOCK_METHOD0(Stop, void()); | 76 MOCK_METHOD0(Stop, void()); |
81 | 77 |
82 private: | 78 private: |
83 virtual ~MockWebContentsTracker() {} | 79 virtual ~MockWebContentsTracker() {} |
84 | 80 |
85 DISALLOW_COPY_AND_ASSIGN(MockWebContentsTracker); | 81 DISALLOW_COPY_AND_ASSIGN(MockWebContentsTracker); |
86 }; | 82 }; |
87 | 83 |
88 // A fully-functional VirtualAudioInputStream, but methods are mocked to allow | 84 // A fully-functional VirtualAudioInputStream, but methods are mocked to allow |
(...skipping 91 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
180 WebContentsAudioInputStreamTest() | 176 WebContentsAudioInputStreamTest() |
181 : thread_bundle_(new TestBrowserThreadBundle( | 177 : thread_bundle_(new TestBrowserThreadBundle( |
182 TestBrowserThreadBundle::REAL_IO_THREAD)), | 178 TestBrowserThreadBundle::REAL_IO_THREAD)), |
183 audio_thread_("Audio thread"), | 179 audio_thread_("Audio thread"), |
184 mock_mirroring_manager_(new MockAudioMirroringManager()), | 180 mock_mirroring_manager_(new MockAudioMirroringManager()), |
185 mock_tracker_(new MockWebContentsTracker()), | 181 mock_tracker_(new MockWebContentsTracker()), |
186 mock_vais_(NULL), | 182 mock_vais_(NULL), |
187 wcais_(NULL), | 183 wcais_(NULL), |
188 destination_(NULL), | 184 destination_(NULL), |
189 current_render_process_id_(kRenderProcessId), | 185 current_render_process_id_(kRenderProcessId), |
190 current_render_view_id_(kRenderViewId), | 186 current_render_frame_id_(kRenderFrameId), |
191 on_data_event_(false, false) { | 187 on_data_event_(false, false) { |
192 audio_thread_.Start(); | 188 audio_thread_.Start(); |
193 } | 189 } |
194 | 190 |
195 virtual ~WebContentsAudioInputStreamTest() { | 191 virtual ~WebContentsAudioInputStreamTest() { |
196 audio_thread_.Stop(); | 192 audio_thread_.Stop(); |
197 thread_bundle_.reset(); | 193 thread_bundle_.reset(); |
198 | 194 |
199 DCHECK(!mock_vais_); | 195 DCHECK(!mock_vais_); |
200 DCHECK(!wcais_); | 196 DCHECK(!wcais_); |
201 EXPECT_FALSE(destination_); | 197 EXPECT_FALSE(destination_); |
202 DCHECK(streams_.empty()); | 198 DCHECK(streams_.empty()); |
203 DCHECK(sources_.empty()); | 199 DCHECK(sources_.empty()); |
204 } | 200 } |
205 | 201 |
206 void Open() { | 202 void Open() { |
207 mock_vais_ = | 203 mock_vais_ = |
208 new MockVirtualAudioInputStream(audio_thread_.message_loop_proxy()); | 204 new MockVirtualAudioInputStream(audio_thread_.message_loop_proxy()); |
209 EXPECT_CALL(*mock_vais_, Open()); | 205 EXPECT_CALL(*mock_vais_, Open()); |
210 EXPECT_CALL(*mock_vais_, Close()); // At Close() time. | 206 EXPECT_CALL(*mock_vais_, Close()); // At Close() time. |
211 | 207 |
212 ASSERT_EQ(kRenderProcessId, current_render_process_id_); | 208 ASSERT_EQ(kRenderProcessId, current_render_process_id_); |
213 ASSERT_EQ(kRenderViewId, current_render_view_id_); | 209 ASSERT_EQ(kRenderFrameId, current_render_frame_id_); |
214 EXPECT_CALL(*mock_tracker_.get(), Start(kRenderProcessId, kRenderViewId, _)) | 210 EXPECT_CALL(*mock_tracker_.get(), |
| 211 Start(kRenderProcessId, kRenderFrameId, _)) |
215 .WillOnce(DoAll( | 212 .WillOnce(DoAll( |
216 SaveArg<2>(&change_callback_), | 213 SaveArg<2>(&change_callback_), |
217 WithArgs<0, 1>(Invoke(&change_callback_, | 214 WithArgs<0, 1>(Invoke(this, |
218 &WebContentsTracker::ChangeCallback::Run)))); | 215 &WebContentsAudioInputStreamTest:: |
| 216 SimulateChangeCallback)))); |
| 217 |
219 EXPECT_CALL(*mock_tracker_.get(), Stop()); // At Close() time. | 218 EXPECT_CALL(*mock_tracker_.get(), Stop()); // At Close() time. |
220 | 219 |
221 wcais_ = new WebContentsAudioInputStream( | 220 wcais_ = new WebContentsAudioInputStream( |
222 current_render_process_id_, current_render_view_id_, | 221 current_render_process_id_, current_render_frame_id_, |
223 mock_mirroring_manager_.get(), | 222 mock_mirroring_manager_.get(), |
224 mock_tracker_, mock_vais_); | 223 mock_tracker_, mock_vais_); |
225 wcais_->Open(); | 224 wcais_->Open(); |
226 } | 225 } |
227 | 226 |
228 void Start() { | 227 void Start() { |
229 EXPECT_CALL(*mock_vais_, Start(&mock_input_callback_)); | 228 EXPECT_CALL(*mock_vais_, Start(&mock_input_callback_)); |
230 EXPECT_CALL(*mock_vais_, Stop()); // At Stop() time. | 229 EXPECT_CALL(*mock_vais_, Stop()); // At Stop() time. |
231 | 230 |
232 EXPECT_CALL(*mock_mirroring_manager_, | 231 EXPECT_CALL(*mock_mirroring_manager_, StartMirroring(NotNull())) |
233 StartMirroring(kRenderProcessId, kRenderViewId, NotNull())) | 232 .WillOnce(SaveArg<0>(&destination_)) |
234 .WillOnce(SaveArg<2>(&destination_)) | |
235 .RetiresOnSaturation(); | 233 .RetiresOnSaturation(); |
236 // At Stop() time, or when the mirroring target changes: | 234 // At Stop() time, or when the mirroring target changes: |
237 EXPECT_CALL(*mock_mirroring_manager_, | 235 EXPECT_CALL(*mock_mirroring_manager_, StopMirroring(NotNull())) |
238 StopMirroring(kRenderProcessId, kRenderViewId, NotNull())) | |
239 .WillOnce(Assign( | 236 .WillOnce(Assign( |
240 &destination_, | 237 &destination_, |
241 static_cast<AudioMirroringManager::MirroringDestination*>(NULL))) | 238 static_cast<AudioMirroringManager::MirroringDestination*>(NULL))) |
242 .RetiresOnSaturation(); | 239 .RetiresOnSaturation(); |
243 | 240 |
244 EXPECT_CALL(mock_input_callback_, OnData(NotNull(), NotNull(), _, _)) | 241 EXPECT_CALL(mock_input_callback_, OnData(NotNull(), NotNull(), _, _)) |
245 .WillRepeatedly( | 242 .WillRepeatedly( |
246 InvokeWithoutArgs(&on_data_event_, &base::WaitableEvent::Signal)); | 243 InvokeWithoutArgs(&on_data_event_, &base::WaitableEvent::Signal)); |
247 | 244 |
248 wcais_->Start(&mock_input_callback_); | 245 wcais_->Start(&mock_input_callback_); |
(...skipping 53 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
302 out->Close(); // Self-deletes. | 299 out->Close(); // Self-deletes. |
303 ASSERT_TRUE(!sources_.empty()); | 300 ASSERT_TRUE(!sources_.empty()); |
304 delete sources_.front(); | 301 delete sources_.front(); |
305 sources_.pop_front(); | 302 sources_.pop_front(); |
306 } | 303 } |
307 | 304 |
308 void ChangeMirroringTarget() { | 305 void ChangeMirroringTarget() { |
309 const int next_render_process_id = | 306 const int next_render_process_id = |
310 current_render_process_id_ == kRenderProcessId ? | 307 current_render_process_id_ == kRenderProcessId ? |
311 kAnotherRenderProcessId : kRenderProcessId; | 308 kAnotherRenderProcessId : kRenderProcessId; |
312 const int next_render_view_id = | 309 const int next_render_frame_id = |
313 current_render_view_id_ == kRenderViewId ? | 310 current_render_frame_id_ == kRenderFrameId ? |
314 kAnotherRenderViewId : kRenderViewId; | 311 kAnotherRenderFrameId : kRenderFrameId; |
315 | 312 |
316 EXPECT_CALL(*mock_mirroring_manager_, | 313 EXPECT_CALL(*mock_mirroring_manager_, StartMirroring(NotNull())) |
317 StartMirroring(next_render_process_id, next_render_view_id, | 314 .WillOnce(SaveArg<0>(&destination_)) |
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(); | 315 .RetiresOnSaturation(); |
329 | 316 |
330 // Simulate OnTargetChange() callback from WebContentsTracker. | 317 SimulateChangeCallback(next_render_process_id, next_render_frame_id); |
331 EXPECT_FALSE(change_callback_.is_null()); | |
332 change_callback_.Run(next_render_process_id, next_render_view_id); | |
333 | 318 |
334 current_render_process_id_ = next_render_process_id; | 319 current_render_process_id_ = next_render_process_id; |
335 current_render_view_id_ = next_render_view_id; | 320 current_render_frame_id_ = next_render_frame_id; |
336 } | 321 } |
337 | 322 |
338 void LoseMirroringTarget() { | 323 void LoseMirroringTarget() { |
339 EXPECT_CALL(mock_input_callback_, OnError(_)); | 324 EXPECT_CALL(mock_input_callback_, OnError(_)); |
340 | 325 |
341 // Simulate OnTargetChange() callback from WebContentsTracker. | 326 SimulateChangeCallback(-1, -1); |
342 EXPECT_FALSE(change_callback_.is_null()); | |
343 change_callback_.Run(-1, -1); | |
344 } | 327 } |
345 | 328 |
346 void Stop() { | 329 void Stop() { |
347 wcais_->Stop(); | 330 wcais_->Stop(); |
348 } | 331 } |
349 | 332 |
350 void Close() { | 333 void Close() { |
351 // WebContentsAudioInputStream self-destructs on Close(). Its internal | 334 // WebContentsAudioInputStream self-destructs on Close(). Its internal |
352 // objects hang around until they are no longer referred to (e.g., as tasks | 335 // objects hang around until they are no longer referred to (e.g., as tasks |
353 // on other threads shut things down). | 336 // on other threads shut things down). |
354 wcais_->Close(); | 337 wcais_->Close(); |
355 wcais_ = NULL; | 338 wcais_ = NULL; |
356 mock_vais_ = NULL; | 339 mock_vais_ = NULL; |
357 } | 340 } |
358 | 341 |
359 void RunOnAudioThread(const base::Closure& closure) { | 342 void RunOnAudioThread(const base::Closure& closure) { |
360 audio_thread_.message_loop()->PostTask(FROM_HERE, closure); | 343 audio_thread_.message_loop()->PostTask(FROM_HERE, closure); |
361 } | 344 } |
362 | 345 |
363 // Block the calling thread until OnData() callbacks are being made. | 346 // Block the calling thread until OnData() callbacks are being made. |
364 void WaitForData() { | 347 void WaitForData() { |
365 // Note: Arbitrarily chosen, but more iterations causes tests to take | 348 // Note: Arbitrarily chosen, but more iterations causes tests to take |
366 // significantly more time. | 349 // significantly more time. |
367 static const int kNumIterations = 3; | 350 static const int kNumIterations = 3; |
368 for (int i = 0; i < kNumIterations; ++i) | 351 for (int i = 0; i < kNumIterations; ++i) |
369 on_data_event_.Wait(); | 352 on_data_event_.Wait(); |
370 } | 353 } |
371 | 354 |
372 private: | 355 private: |
| 356 void SimulateChangeCallback(int render_process_id, int render_frame_id) { |
| 357 ASSERT_FALSE(change_callback_.is_null()); |
| 358 if (render_process_id == -1 || render_frame_id == -1) { |
| 359 change_callback_.Run(NULL); |
| 360 } else { |
| 361 // For our tests, any non-NULL value will suffice since it will not be |
| 362 // dereferenced. |
| 363 change_callback_.Run(reinterpret_cast<RenderWidgetHost*>(0xdeadbee5)); |
| 364 } |
| 365 } |
| 366 |
373 scoped_ptr<TestBrowserThreadBundle> thread_bundle_; | 367 scoped_ptr<TestBrowserThreadBundle> thread_bundle_; |
374 base::Thread audio_thread_; | 368 base::Thread audio_thread_; |
375 | 369 |
376 scoped_ptr<MockAudioMirroringManager> mock_mirroring_manager_; | 370 scoped_ptr<MockAudioMirroringManager> mock_mirroring_manager_; |
377 scoped_refptr<MockWebContentsTracker> mock_tracker_; | 371 scoped_refptr<MockWebContentsTracker> mock_tracker_; |
378 | 372 |
379 MockVirtualAudioInputStream* mock_vais_; // Owned by wcais_. | 373 MockVirtualAudioInputStream* mock_vais_; // Owned by wcais_. |
380 WebContentsAudioInputStream* wcais_; // Self-destructs on Close(). | 374 WebContentsAudioInputStream* wcais_; // Self-destructs on Close(). |
381 | 375 |
382 // Mock consumer of audio data. | 376 // Mock consumer of audio data. |
383 MockAudioInputCallback mock_input_callback_; | 377 MockAudioInputCallback mock_input_callback_; |
384 | 378 |
385 // Provided by WebContentsAudioInputStream to the mock WebContentsTracker. | 379 // Provided by WebContentsAudioInputStream to the mock WebContentsTracker. |
386 // This callback is saved here, and test code will invoke it to simulate | 380 // This callback is saved here, and test code will invoke it to simulate |
387 // target change events. | 381 // target change events. |
388 WebContentsTracker::ChangeCallback change_callback_; | 382 WebContentsTracker::ChangeCallback change_callback_; |
389 | 383 |
390 // Provided by WebContentsAudioInputStream to the mock AudioMirroringManager. | 384 // Provided by WebContentsAudioInputStream to the mock AudioMirroringManager. |
391 // A pointer to the implementation is saved here, and test code will invoke it | 385 // 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. | 386 // to simulate: 1) calls to AddInput(); and 2) diverting audio data. |
393 AudioMirroringManager::MirroringDestination* destination_; | 387 AudioMirroringManager::MirroringDestination* destination_; |
394 | 388 |
395 // Current target RenderView. These get flipped in ChangedMirroringTarget(). | 389 // Current target RenderFrame. These get flipped in ChangedMirroringTarget(). |
396 int current_render_process_id_; | 390 int current_render_process_id_; |
397 int current_render_view_id_; | 391 int current_render_frame_id_; |
398 | 392 |
399 // Streams provided by calls to WebContentsAudioInputStream::AddInput(). Each | 393 // Streams provided by calls to WebContentsAudioInputStream::AddInput(). Each |
400 // is started with a simulated source of audio data. | 394 // is started with a simulated source of audio data. |
401 std::list<AudioOutputStream*> streams_; | 395 std::list<AudioOutputStream*> streams_; |
402 std::list<SineWaveAudioSource*> sources_; // 1:1 with elements in streams_. | 396 std::list<SineWaveAudioSource*> sources_; // 1:1 with elements in streams_. |
403 | 397 |
404 base::WaitableEvent on_data_event_; | 398 base::WaitableEvent on_data_event_; |
405 | 399 |
406 DISALLOW_COPY_AND_ASSIGN(WebContentsAudioInputStreamTest); | 400 DISALLOW_COPY_AND_ASSIGN(WebContentsAudioInputStreamTest); |
407 }; | 401 }; |
(...skipping 97 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
505 WaitForData(); | 499 WaitForData(); |
506 RUN_ON_AUDIO_THREAD(RemoveOneInputInFIFOOrder); | 500 RUN_ON_AUDIO_THREAD(RemoveOneInputInFIFOOrder); |
507 WaitForData(); | 501 WaitForData(); |
508 RUN_ON_AUDIO_THREAD(ChangeMirroringTarget); | 502 RUN_ON_AUDIO_THREAD(ChangeMirroringTarget); |
509 RUN_ON_AUDIO_THREAD(RemoveOneInputInFIFOOrder); | 503 RUN_ON_AUDIO_THREAD(RemoveOneInputInFIFOOrder); |
510 RUN_ON_AUDIO_THREAD(Stop); | 504 RUN_ON_AUDIO_THREAD(Stop); |
511 RUN_ON_AUDIO_THREAD(Close); | 505 RUN_ON_AUDIO_THREAD(Close); |
512 } | 506 } |
513 | 507 |
514 } // namespace content | 508 } // namespace content |
OLD | NEW |