| OLD | NEW |
| 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 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 | 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 "chrome/browser/media/media_capture_devices_dispatcher.h" | 5 #include "chrome/browser/media/media_capture_devices_dispatcher.h" |
| 6 | 6 |
| 7 #include "base/command_line.h" | 7 #include "base/command_line.h" |
| 8 #include "base/logging.h" | 8 #include "base/logging.h" |
| 9 #include "base/prefs/pref_service.h" | 9 #include "base/prefs/pref_service.h" |
| 10 #include "base/prefs/scoped_user_pref_update.h" | 10 #include "base/prefs/scoped_user_pref_update.h" |
| (...skipping 282 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 293 | 293 |
| 294 void MediaCaptureDevicesDispatcher::ProcessDesktopCaptureAccessRequest( | 294 void MediaCaptureDevicesDispatcher::ProcessDesktopCaptureAccessRequest( |
| 295 content::WebContents* web_contents, | 295 content::WebContents* web_contents, |
| 296 const content::MediaStreamRequest& request, | 296 const content::MediaStreamRequest& request, |
| 297 const content::MediaResponseCallback& callback, | 297 const content::MediaResponseCallback& callback, |
| 298 const extensions::Extension* extension) { | 298 const extensions::Extension* extension) { |
| 299 content::MediaStreamDevices devices; | 299 content::MediaStreamDevices devices; |
| 300 scoped_ptr<content::MediaStreamUI> ui; | 300 scoped_ptr<content::MediaStreamUI> ui; |
| 301 | 301 |
| 302 if (request.video_type != content::MEDIA_DESKTOP_VIDEO_CAPTURE) { | 302 if (request.video_type != content::MEDIA_DESKTOP_VIDEO_CAPTURE) { |
| 303 callback.Run(devices, ui.Pass()); | 303 callback.Run(devices, content::MEDIA_DEVICE_INVALID_STATE, ui.Pass()); |
| 304 return; | 304 return; |
| 305 } | 305 } |
| 306 | 306 |
| 307 // If the device id wasn't specified then this is a screen capture request | 307 // If the device id wasn't specified then this is a screen capture request |
| 308 // (i.e. chooseDesktopMedia() API wasn't used to generate device id). | 308 // (i.e. chooseDesktopMedia() API wasn't used to generate device id). |
| 309 if (request.requested_video_device_id.empty()) { | 309 if (request.requested_video_device_id.empty()) { |
| 310 ProcessScreenCaptureAccessRequest( | 310 ProcessScreenCaptureAccessRequest( |
| 311 web_contents, request, callback, extension); | 311 web_contents, request, callback, extension); |
| 312 return; | 312 return; |
| 313 } | 313 } |
| 314 | 314 |
| 315 // Resolve DesktopMediaID for the specified device id. | 315 // Resolve DesktopMediaID for the specified device id. |
| 316 content::DesktopMediaID media_id = | 316 content::DesktopMediaID media_id = |
| 317 GetDesktopStreamsRegistry()->RequestMediaForStreamId( | 317 GetDesktopStreamsRegistry()->RequestMediaForStreamId( |
| 318 request.requested_video_device_id, request.render_process_id, | 318 request.requested_video_device_id, request.render_process_id, |
| 319 request.render_view_id, request.security_origin); | 319 request.render_view_id, request.security_origin); |
| 320 | 320 |
| 321 // Received invalid device id. | 321 // Received invalid device id. |
| 322 if (media_id.type == content::DesktopMediaID::TYPE_NONE) { | 322 if (media_id.type == content::DesktopMediaID::TYPE_NONE) { |
| 323 callback.Run(devices, ui.Pass()); | 323 callback.Run(devices, content::MEDIA_DEVICE_INVALID_STATE, ui.Pass()); |
| 324 return; | 324 return; |
| 325 } | 325 } |
| 326 | 326 |
| 327 bool loopback_audio_supported = false; | 327 bool loopback_audio_supported = false; |
| 328 #if defined(USE_CRAS) || defined(OS_WIN) | 328 #if defined(USE_CRAS) || defined(OS_WIN) |
| 329 // Currently loopback audio capture is supported only on Windows and ChromeOS. | 329 // Currently loopback audio capture is supported only on Windows and ChromeOS. |
| 330 loopback_audio_supported = true; | 330 loopback_audio_supported = true; |
| 331 #endif | 331 #endif |
| 332 | 332 |
| 333 // Audio is only supported for screen capture streams. | 333 // Audio is only supported for screen capture streams. |
| 334 bool capture_audio = | 334 bool capture_audio = |
| 335 (media_id.type == content::DesktopMediaID::TYPE_SCREEN && | 335 (media_id.type == content::DesktopMediaID::TYPE_SCREEN && |
| 336 request.audio_type == content::MEDIA_LOOPBACK_AUDIO_CAPTURE && | 336 request.audio_type == content::MEDIA_LOOPBACK_AUDIO_CAPTURE && |
| 337 loopback_audio_supported); | 337 loopback_audio_supported); |
| 338 | 338 |
| 339 ui = GetDevicesForDesktopCapture( | 339 ui = GetDevicesForDesktopCapture( |
| 340 devices, media_id, capture_audio, true, | 340 devices, media_id, capture_audio, true, |
| 341 GetApplicationTitle(web_contents, extension)); | 341 GetApplicationTitle(web_contents, extension)); |
| 342 | 342 |
| 343 callback.Run(devices, ui.Pass()); | 343 callback.Run(devices, content::MEDIA_DEVICE_OK, ui.Pass()); |
| 344 } | 344 } |
| 345 | 345 |
| 346 void MediaCaptureDevicesDispatcher::ProcessScreenCaptureAccessRequest( | 346 void MediaCaptureDevicesDispatcher::ProcessScreenCaptureAccessRequest( |
| 347 content::WebContents* web_contents, | 347 content::WebContents* web_contents, |
| 348 const content::MediaStreamRequest& request, | 348 const content::MediaStreamRequest& request, |
| 349 const content::MediaResponseCallback& callback, | 349 const content::MediaResponseCallback& callback, |
| 350 const extensions::Extension* extension) { | 350 const extensions::Extension* extension) { |
| 351 content::MediaStreamDevices devices; | 351 content::MediaStreamDevices devices; |
| 352 scoped_ptr<content::MediaStreamUI> ui; | 352 scoped_ptr<content::MediaStreamUI> ui; |
| 353 | 353 |
| (...skipping 68 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 422 | 422 |
| 423 // Unless we're being invoked from a component extension, register to | 423 // Unless we're being invoked from a component extension, register to |
| 424 // display the notification for stream capture. | 424 // display the notification for stream capture. |
| 425 bool display_notification = !component_extension; | 425 bool display_notification = !component_extension; |
| 426 | 426 |
| 427 ui = GetDevicesForDesktopCapture(devices, screen_id, capture_audio, | 427 ui = GetDevicesForDesktopCapture(devices, screen_id, capture_audio, |
| 428 display_notification, application_title); | 428 display_notification, application_title); |
| 429 } | 429 } |
| 430 } | 430 } |
| 431 | 431 |
| 432 callback.Run(devices, ui.Pass()); | 432 callback.Run( |
| 433 devices, |
| 434 devices.empty() ? content::MEDIA_DEVICE_INVALID_STATE : |
| 435 content::MEDIA_DEVICE_OK, |
| 436 ui.Pass()); |
| 433 } | 437 } |
| 434 | 438 |
| 435 void MediaCaptureDevicesDispatcher::ProcessTabCaptureAccessRequest( | 439 void MediaCaptureDevicesDispatcher::ProcessTabCaptureAccessRequest( |
| 436 content::WebContents* web_contents, | 440 content::WebContents* web_contents, |
| 437 const content::MediaStreamRequest& request, | 441 const content::MediaStreamRequest& request, |
| 438 const content::MediaResponseCallback& callback, | 442 const content::MediaResponseCallback& callback, |
| 439 const extensions::Extension* extension) { | 443 const extensions::Extension* extension) { |
| 440 content::MediaStreamDevices devices; | 444 content::MediaStreamDevices devices; |
| 441 scoped_ptr<content::MediaStreamUI> ui; | 445 scoped_ptr<content::MediaStreamUI> ui; |
| 442 | 446 |
| 443 #if defined(OS_ANDROID) | 447 #if defined(OS_ANDROID) |
| 444 // Tab capture is not supported on Android. | 448 // Tab capture is not supported on Android. |
| 445 callback.Run(devices, ui.Pass()); | 449 callback.Run(devices, ui.Pass()); |
| 446 #else // defined(OS_ANDROID) | 450 #else // defined(OS_ANDROID) |
| 447 Profile* profile = | 451 Profile* profile = |
| 448 Profile::FromBrowserContext(web_contents->GetBrowserContext()); | 452 Profile::FromBrowserContext(web_contents->GetBrowserContext()); |
| 449 extensions::TabCaptureRegistry* tab_capture_registry = | 453 extensions::TabCaptureRegistry* tab_capture_registry = |
| 450 extensions::TabCaptureRegistry::Get(profile); | 454 extensions::TabCaptureRegistry::Get(profile); |
| 451 if (!tab_capture_registry) { | 455 if (!tab_capture_registry) { |
| 452 NOTREACHED(); | 456 NOTREACHED(); |
| 453 callback.Run(devices, ui.Pass()); | 457 callback.Run(devices, content::MEDIA_DEVICE_INVALID_STATE, ui.Pass()); |
| 454 return; | 458 return; |
| 455 } | 459 } |
| 456 bool tab_capture_allowed = | 460 bool tab_capture_allowed = |
| 457 tab_capture_registry->VerifyRequest(request.render_process_id, | 461 tab_capture_registry->VerifyRequest(request.render_process_id, |
| 458 request.render_view_id); | 462 request.render_view_id); |
| 459 | 463 |
| 460 if (request.audio_type == content::MEDIA_TAB_AUDIO_CAPTURE && | 464 if (request.audio_type == content::MEDIA_TAB_AUDIO_CAPTURE && |
| 461 tab_capture_allowed && | 465 tab_capture_allowed && |
| 462 extension->HasAPIPermission(extensions::APIPermission::kTabCapture)) { | 466 extension->HasAPIPermission(extensions::APIPermission::kTabCapture)) { |
| 463 devices.push_back(content::MediaStreamDevice( | 467 devices.push_back(content::MediaStreamDevice( |
| 464 content::MEDIA_TAB_AUDIO_CAPTURE, std::string(), std::string())); | 468 content::MEDIA_TAB_AUDIO_CAPTURE, std::string(), std::string())); |
| 465 } | 469 } |
| 466 | 470 |
| 467 if (request.video_type == content::MEDIA_TAB_VIDEO_CAPTURE && | 471 if (request.video_type == content::MEDIA_TAB_VIDEO_CAPTURE && |
| 468 tab_capture_allowed && | 472 tab_capture_allowed && |
| 469 extension->HasAPIPermission(extensions::APIPermission::kTabCapture)) { | 473 extension->HasAPIPermission(extensions::APIPermission::kTabCapture)) { |
| 470 devices.push_back(content::MediaStreamDevice( | 474 devices.push_back(content::MediaStreamDevice( |
| 471 content::MEDIA_TAB_VIDEO_CAPTURE, std::string(), std::string())); | 475 content::MEDIA_TAB_VIDEO_CAPTURE, std::string(), std::string())); |
| 472 } | 476 } |
| 473 | 477 |
| 474 if (!devices.empty()) { | 478 if (!devices.empty()) { |
| 475 ui = media_stream_capture_indicator_->RegisterMediaStream( | 479 ui = media_stream_capture_indicator_->RegisterMediaStream( |
| 476 web_contents, devices); | 480 web_contents, devices); |
| 477 } | 481 } |
| 478 callback.Run(devices, ui.Pass()); | 482 callback.Run( |
| 483 devices, |
| 484 devices.empty() ? content::MEDIA_DEVICE_INVALID_STATE : |
| 485 content::MEDIA_DEVICE_OK, |
| 486 ui.Pass()); |
| 479 #endif // !defined(OS_ANDROID) | 487 #endif // !defined(OS_ANDROID) |
| 480 } | 488 } |
| 481 | 489 |
| 482 void MediaCaptureDevicesDispatcher:: | 490 void MediaCaptureDevicesDispatcher:: |
| 483 ProcessMediaAccessRequestFromPlatformAppOrExtension( | 491 ProcessMediaAccessRequestFromPlatformAppOrExtension( |
| 484 content::WebContents* web_contents, | 492 content::WebContents* web_contents, |
| 485 const content::MediaStreamRequest& request, | 493 const content::MediaStreamRequest& request, |
| 486 const content::MediaResponseCallback& callback, | 494 const content::MediaResponseCallback& callback, |
| 487 const extensions::Extension* extension) { | 495 const extensions::Extension* extension) { |
| 488 content::MediaStreamDevices devices; | 496 content::MediaStreamDevices devices; |
| 489 Profile* profile = | 497 Profile* profile = |
| 490 Profile::FromBrowserContext(web_contents->GetBrowserContext()); | 498 Profile::FromBrowserContext(web_contents->GetBrowserContext()); |
| 491 | 499 |
| 492 if (request.audio_type == content::MEDIA_DEVICE_AUDIO_CAPTURE && | 500 if (request.audio_type == content::MEDIA_DEVICE_AUDIO_CAPTURE && |
| 493 extension->HasAPIPermission(extensions::APIPermission::kAudioCapture)) { | 501 extension->HasAPIPermission(extensions::APIPermission::kAudioCapture)) { |
| 494 GetDefaultDevicesForProfile(profile, true, false, &devices); | 502 GetDefaultDevicesForProfile(profile, true, false, &devices); |
| 495 } | 503 } |
| 496 | 504 |
| 497 if (request.video_type == content::MEDIA_DEVICE_VIDEO_CAPTURE && | 505 if (request.video_type == content::MEDIA_DEVICE_VIDEO_CAPTURE && |
| 498 extension->HasAPIPermission(extensions::APIPermission::kVideoCapture)) { | 506 extension->HasAPIPermission(extensions::APIPermission::kVideoCapture)) { |
| 499 GetDefaultDevicesForProfile(profile, false, true, &devices); | 507 GetDefaultDevicesForProfile(profile, false, true, &devices); |
| 500 } | 508 } |
| 501 | 509 |
| 502 scoped_ptr<content::MediaStreamUI> ui; | 510 scoped_ptr<content::MediaStreamUI> ui; |
| 503 if (!devices.empty()) { | 511 if (!devices.empty()) { |
| 504 ui = media_stream_capture_indicator_->RegisterMediaStream( | 512 ui = media_stream_capture_indicator_->RegisterMediaStream( |
| 505 web_contents, devices); | 513 web_contents, devices); |
| 506 } | 514 } |
| 507 callback.Run(devices, ui.Pass()); | 515 callback.Run( |
| 516 devices, |
| 517 devices.empty() ? content::MEDIA_DEVICE_INVALID_STATE : |
| 518 content::MEDIA_DEVICE_OK, |
| 519 ui.Pass()); |
| 508 } | 520 } |
| 509 | 521 |
| 510 void MediaCaptureDevicesDispatcher::ProcessRegularMediaAccessRequest( | 522 void MediaCaptureDevicesDispatcher::ProcessRegularMediaAccessRequest( |
| 511 content::WebContents* web_contents, | 523 content::WebContents* web_contents, |
| 512 const content::MediaStreamRequest& request, | 524 const content::MediaStreamRequest& request, |
| 513 const content::MediaResponseCallback& callback) { | 525 const content::MediaResponseCallback& callback) { |
| 514 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | 526 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
| 515 | 527 |
| 516 RequestsQueue& queue = pending_requests_[web_contents]; | 528 RequestsQueue& queue = pending_requests_[web_contents]; |
| 517 queue.push_back(PendingAccessRequest(request, callback)); | 529 queue.push_back(PendingAccessRequest(request, callback)); |
| (...skipping 34 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 552 // when we've transitioned to bubbles. (crbug/337458) | 564 // when we've transitioned to bubbles. (crbug/337458) |
| 553 MediaStreamInfoBarDelegate::Create( | 565 MediaStreamInfoBarDelegate::Create( |
| 554 web_contents, it->second.front().request, | 566 web_contents, it->second.front().request, |
| 555 base::Bind(&MediaCaptureDevicesDispatcher::OnAccessRequestResponse, | 567 base::Bind(&MediaCaptureDevicesDispatcher::OnAccessRequestResponse, |
| 556 base::Unretained(this), web_contents)); | 568 base::Unretained(this), web_contents)); |
| 557 } | 569 } |
| 558 | 570 |
| 559 void MediaCaptureDevicesDispatcher::OnAccessRequestResponse( | 571 void MediaCaptureDevicesDispatcher::OnAccessRequestResponse( |
| 560 content::WebContents* web_contents, | 572 content::WebContents* web_contents, |
| 561 const content::MediaStreamDevices& devices, | 573 const content::MediaStreamDevices& devices, |
| 574 content::MediaStreamRequestResult result, |
| 562 scoped_ptr<content::MediaStreamUI> ui) { | 575 scoped_ptr<content::MediaStreamUI> ui) { |
| 563 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | 576 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
| 564 | 577 |
| 565 std::map<content::WebContents*, RequestsQueue>::iterator it = | 578 std::map<content::WebContents*, RequestsQueue>::iterator it = |
| 566 pending_requests_.find(web_contents); | 579 pending_requests_.find(web_contents); |
| 567 if (it == pending_requests_.end()) { | 580 if (it == pending_requests_.end()) { |
| 568 // WebContents has been destroyed. Don't need to do anything. | 581 // WebContents has been destroyed. Don't need to do anything. |
| 569 return; | 582 return; |
| 570 } | 583 } |
| 571 | 584 |
| 572 RequestsQueue& queue(it->second); | 585 RequestsQueue& queue(it->second); |
| 573 if (queue.empty()) | 586 if (queue.empty()) |
| 574 return; | 587 return; |
| 575 | 588 |
| 576 content::MediaResponseCallback callback = queue.front().callback; | 589 content::MediaResponseCallback callback = queue.front().callback; |
| 577 queue.pop_front(); | 590 queue.pop_front(); |
| 578 | 591 |
| 579 if (!queue.empty()) { | 592 if (!queue.empty()) { |
| 580 // Post a task to process next queued request. It has to be done | 593 // Post a task to process next queued request. It has to be done |
| 581 // asynchronously to make sure that calling infobar is not destroyed until | 594 // asynchronously to make sure that calling infobar is not destroyed until |
| 582 // after this function returns. | 595 // after this function returns. |
| 583 BrowserThread::PostTask( | 596 BrowserThread::PostTask( |
| 584 BrowserThread::UI, FROM_HERE, | 597 BrowserThread::UI, FROM_HERE, |
| 585 base::Bind(&MediaCaptureDevicesDispatcher::ProcessQueuedAccessRequest, | 598 base::Bind(&MediaCaptureDevicesDispatcher::ProcessQueuedAccessRequest, |
| 586 base::Unretained(this), web_contents)); | 599 base::Unretained(this), web_contents)); |
| 587 } | 600 } |
| 588 | 601 |
| 589 callback.Run(devices, ui.Pass()); | 602 callback.Run(devices, result, ui.Pass()); |
| 590 } | 603 } |
| 591 | 604 |
| 592 void MediaCaptureDevicesDispatcher::GetDefaultDevicesForProfile( | 605 void MediaCaptureDevicesDispatcher::GetDefaultDevicesForProfile( |
| 593 Profile* profile, | 606 Profile* profile, |
| 594 bool audio, | 607 bool audio, |
| 595 bool video, | 608 bool video, |
| 596 content::MediaStreamDevices* devices) { | 609 content::MediaStreamDevices* devices) { |
| 597 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | 610 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
| 598 DCHECK(audio || video); | 611 DCHECK(audio || video); |
| 599 | 612 |
| (...skipping 224 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 824 int render_frame_id) { | 837 int render_frame_id) { |
| 825 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | 838 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
| 826 FOR_EACH_OBSERVER(Observer, observers_, | 839 FOR_EACH_OBSERVER(Observer, observers_, |
| 827 OnCreatingAudioStream(render_process_id, render_frame_id)); | 840 OnCreatingAudioStream(render_process_id, render_frame_id)); |
| 828 } | 841 } |
| 829 | 842 |
| 830 bool MediaCaptureDevicesDispatcher::IsDesktopCaptureInProgress() { | 843 bool MediaCaptureDevicesDispatcher::IsDesktopCaptureInProgress() { |
| 831 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | 844 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
| 832 return desktop_capture_sessions_.size() > 0; | 845 return desktop_capture_sessions_.size() > 0; |
| 833 } | 846 } |
| OLD | NEW |