| 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 |