| 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::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::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::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::INVALID_STATE: content::OK, |
| 435 ui.Pass()); |
| 433 } | 436 } |
| 434 | 437 |
| 435 void MediaCaptureDevicesDispatcher::ProcessTabCaptureAccessRequest( | 438 void MediaCaptureDevicesDispatcher::ProcessTabCaptureAccessRequest( |
| 436 content::WebContents* web_contents, | 439 content::WebContents* web_contents, |
| 437 const content::MediaStreamRequest& request, | 440 const content::MediaStreamRequest& request, |
| 438 const content::MediaResponseCallback& callback, | 441 const content::MediaResponseCallback& callback, |
| 439 const extensions::Extension* extension) { | 442 const extensions::Extension* extension) { |
| 440 content::MediaStreamDevices devices; | 443 content::MediaStreamDevices devices; |
| 441 scoped_ptr<content::MediaStreamUI> ui; | 444 scoped_ptr<content::MediaStreamUI> ui; |
| 442 | 445 |
| 443 #if defined(OS_ANDROID) | 446 #if defined(OS_ANDROID) |
| 444 // Tab capture is not supported on Android. | 447 // Tab capture is not supported on Android. |
| 445 callback.Run(devices, ui.Pass()); | 448 callback.Run(devices, ui.Pass()); |
| 446 #else // defined(OS_ANDROID) | 449 #else // defined(OS_ANDROID) |
| 447 Profile* profile = | 450 Profile* profile = |
| 448 Profile::FromBrowserContext(web_contents->GetBrowserContext()); | 451 Profile::FromBrowserContext(web_contents->GetBrowserContext()); |
| 449 extensions::TabCaptureRegistry* tab_capture_registry = | 452 extensions::TabCaptureRegistry* tab_capture_registry = |
| 450 extensions::TabCaptureRegistry::Get(profile); | 453 extensions::TabCaptureRegistry::Get(profile); |
| 451 if (!tab_capture_registry) { | 454 if (!tab_capture_registry) { |
| 452 NOTREACHED(); | 455 NOTREACHED(); |
| 453 callback.Run(devices, ui.Pass()); | 456 callback.Run(devices, content::INVALID_STATE, ui.Pass()); |
| 454 return; | 457 return; |
| 455 } | 458 } |
| 456 bool tab_capture_allowed = | 459 bool tab_capture_allowed = |
| 457 tab_capture_registry->VerifyRequest(request.render_process_id, | 460 tab_capture_registry->VerifyRequest(request.render_process_id, |
| 458 request.render_view_id); | 461 request.render_view_id); |
| 459 | 462 |
| 460 if (request.audio_type == content::MEDIA_TAB_AUDIO_CAPTURE && | 463 if (request.audio_type == content::MEDIA_TAB_AUDIO_CAPTURE && |
| 461 tab_capture_allowed && | 464 tab_capture_allowed && |
| 462 extension->HasAPIPermission(extensions::APIPermission::kTabCapture)) { | 465 extension->HasAPIPermission(extensions::APIPermission::kTabCapture)) { |
| 463 devices.push_back(content::MediaStreamDevice( | 466 devices.push_back(content::MediaStreamDevice( |
| 464 content::MEDIA_TAB_AUDIO_CAPTURE, std::string(), std::string())); | 467 content::MEDIA_TAB_AUDIO_CAPTURE, std::string(), std::string())); |
| 465 } | 468 } |
| 466 | 469 |
| 467 if (request.video_type == content::MEDIA_TAB_VIDEO_CAPTURE && | 470 if (request.video_type == content::MEDIA_TAB_VIDEO_CAPTURE && |
| 468 tab_capture_allowed && | 471 tab_capture_allowed && |
| 469 extension->HasAPIPermission(extensions::APIPermission::kTabCapture)) { | 472 extension->HasAPIPermission(extensions::APIPermission::kTabCapture)) { |
| 470 devices.push_back(content::MediaStreamDevice( | 473 devices.push_back(content::MediaStreamDevice( |
| 471 content::MEDIA_TAB_VIDEO_CAPTURE, std::string(), std::string())); | 474 content::MEDIA_TAB_VIDEO_CAPTURE, std::string(), std::string())); |
| 472 } | 475 } |
| 473 | 476 |
| 474 if (!devices.empty()) { | 477 if (!devices.empty()) { |
| 475 ui = media_stream_capture_indicator_->RegisterMediaStream( | 478 ui = media_stream_capture_indicator_->RegisterMediaStream( |
| 476 web_contents, devices); | 479 web_contents, devices); |
| 477 } | 480 } |
| 478 callback.Run(devices, ui.Pass()); | 481 callback.Run( |
| 482 devices, |
| 483 devices.empty() ? content::INVALID_STATE: content::OK, |
| 484 ui.Pass()); |
| 479 #endif // !defined(OS_ANDROID) | 485 #endif // !defined(OS_ANDROID) |
| 480 } | 486 } |
| 481 | 487 |
| 482 void MediaCaptureDevicesDispatcher:: | 488 void MediaCaptureDevicesDispatcher:: |
| 483 ProcessMediaAccessRequestFromPlatformAppOrExtension( | 489 ProcessMediaAccessRequestFromPlatformAppOrExtension( |
| 484 content::WebContents* web_contents, | 490 content::WebContents* web_contents, |
| 485 const content::MediaStreamRequest& request, | 491 const content::MediaStreamRequest& request, |
| 486 const content::MediaResponseCallback& callback, | 492 const content::MediaResponseCallback& callback, |
| 487 const extensions::Extension* extension) { | 493 const extensions::Extension* extension) { |
| 488 content::MediaStreamDevices devices; | 494 content::MediaStreamDevices devices; |
| 489 Profile* profile = | 495 Profile* profile = |
| 490 Profile::FromBrowserContext(web_contents->GetBrowserContext()); | 496 Profile::FromBrowserContext(web_contents->GetBrowserContext()); |
| 491 | 497 |
| 492 if (request.audio_type == content::MEDIA_DEVICE_AUDIO_CAPTURE && | 498 if (request.audio_type == content::MEDIA_DEVICE_AUDIO_CAPTURE && |
| 493 extension->HasAPIPermission(extensions::APIPermission::kAudioCapture)) { | 499 extension->HasAPIPermission(extensions::APIPermission::kAudioCapture)) { |
| 494 GetDefaultDevicesForProfile(profile, true, false, &devices); | 500 GetDefaultDevicesForProfile(profile, true, false, &devices); |
| 495 } | 501 } |
| 496 | 502 |
| 497 if (request.video_type == content::MEDIA_DEVICE_VIDEO_CAPTURE && | 503 if (request.video_type == content::MEDIA_DEVICE_VIDEO_CAPTURE && |
| 498 extension->HasAPIPermission(extensions::APIPermission::kVideoCapture)) { | 504 extension->HasAPIPermission(extensions::APIPermission::kVideoCapture)) { |
| 499 GetDefaultDevicesForProfile(profile, false, true, &devices); | 505 GetDefaultDevicesForProfile(profile, false, true, &devices); |
| 500 } | 506 } |
| 501 | 507 |
| 502 scoped_ptr<content::MediaStreamUI> ui; | 508 scoped_ptr<content::MediaStreamUI> ui; |
| 503 if (!devices.empty()) { | 509 if (!devices.empty()) { |
| 504 ui = media_stream_capture_indicator_->RegisterMediaStream( | 510 ui = media_stream_capture_indicator_->RegisterMediaStream( |
| 505 web_contents, devices); | 511 web_contents, devices); |
| 506 } | 512 } |
| 507 callback.Run(devices, ui.Pass()); | 513 callback.Run( |
| 514 devices, |
| 515 devices.empty() ? content::INVALID_STATE: content::OK, |
| 516 ui.Pass()); |
| 508 } | 517 } |
| 509 | 518 |
| 510 void MediaCaptureDevicesDispatcher::ProcessRegularMediaAccessRequest( | 519 void MediaCaptureDevicesDispatcher::ProcessRegularMediaAccessRequest( |
| 511 content::WebContents* web_contents, | 520 content::WebContents* web_contents, |
| 512 const content::MediaStreamRequest& request, | 521 const content::MediaStreamRequest& request, |
| 513 const content::MediaResponseCallback& callback) { | 522 const content::MediaResponseCallback& callback) { |
| 514 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | 523 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
| 515 | 524 |
| 516 RequestsQueue& queue = pending_requests_[web_contents]; | 525 RequestsQueue& queue = pending_requests_[web_contents]; |
| 517 queue.push_back(PendingAccessRequest(request, callback)); | 526 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) | 561 // when we've transitioned to bubbles. (crbug/337458) |
| 553 MediaStreamInfoBarDelegate::Create( | 562 MediaStreamInfoBarDelegate::Create( |
| 554 web_contents, it->second.front().request, | 563 web_contents, it->second.front().request, |
| 555 base::Bind(&MediaCaptureDevicesDispatcher::OnAccessRequestResponse, | 564 base::Bind(&MediaCaptureDevicesDispatcher::OnAccessRequestResponse, |
| 556 base::Unretained(this), web_contents)); | 565 base::Unretained(this), web_contents)); |
| 557 } | 566 } |
| 558 | 567 |
| 559 void MediaCaptureDevicesDispatcher::OnAccessRequestResponse( | 568 void MediaCaptureDevicesDispatcher::OnAccessRequestResponse( |
| 560 content::WebContents* web_contents, | 569 content::WebContents* web_contents, |
| 561 const content::MediaStreamDevices& devices, | 570 const content::MediaStreamDevices& devices, |
| 571 content::MediaStreamRequestResult result, |
| 562 scoped_ptr<content::MediaStreamUI> ui) { | 572 scoped_ptr<content::MediaStreamUI> ui) { |
| 563 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | 573 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
| 564 | 574 |
| 565 std::map<content::WebContents*, RequestsQueue>::iterator it = | 575 std::map<content::WebContents*, RequestsQueue>::iterator it = |
| 566 pending_requests_.find(web_contents); | 576 pending_requests_.find(web_contents); |
| 567 if (it == pending_requests_.end()) { | 577 if (it == pending_requests_.end()) { |
| 568 // WebContents has been destroyed. Don't need to do anything. | 578 // WebContents has been destroyed. Don't need to do anything. |
| 569 return; | 579 return; |
| 570 } | 580 } |
| 571 | 581 |
| 572 RequestsQueue& queue(it->second); | 582 RequestsQueue& queue(it->second); |
| 573 if (queue.empty()) | 583 if (queue.empty()) |
| 574 return; | 584 return; |
| 575 | 585 |
| 576 content::MediaResponseCallback callback = queue.front().callback; | 586 content::MediaResponseCallback callback = queue.front().callback; |
| 577 queue.pop_front(); | 587 queue.pop_front(); |
| 578 | 588 |
| 579 if (!queue.empty()) { | 589 if (!queue.empty()) { |
| 580 // Post a task to process next queued request. It has to be done | 590 // 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 | 591 // asynchronously to make sure that calling infobar is not destroyed until |
| 582 // after this function returns. | 592 // after this function returns. |
| 583 BrowserThread::PostTask( | 593 BrowserThread::PostTask( |
| 584 BrowserThread::UI, FROM_HERE, | 594 BrowserThread::UI, FROM_HERE, |
| 585 base::Bind(&MediaCaptureDevicesDispatcher::ProcessQueuedAccessRequest, | 595 base::Bind(&MediaCaptureDevicesDispatcher::ProcessQueuedAccessRequest, |
| 586 base::Unretained(this), web_contents)); | 596 base::Unretained(this), web_contents)); |
| 587 } | 597 } |
| 588 | 598 |
| 589 callback.Run(devices, ui.Pass()); | 599 callback.Run(devices, result, ui.Pass()); |
| 590 } | 600 } |
| 591 | 601 |
| 592 void MediaCaptureDevicesDispatcher::GetDefaultDevicesForProfile( | 602 void MediaCaptureDevicesDispatcher::GetDefaultDevicesForProfile( |
| 593 Profile* profile, | 603 Profile* profile, |
| 594 bool audio, | 604 bool audio, |
| 595 bool video, | 605 bool video, |
| 596 content::MediaStreamDevices* devices) { | 606 content::MediaStreamDevices* devices) { |
| 597 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | 607 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
| 598 DCHECK(audio || video); | 608 DCHECK(audio || video); |
| 599 | 609 |
| (...skipping 224 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 824 int render_frame_id) { | 834 int render_frame_id) { |
| 825 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | 835 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
| 826 FOR_EACH_OBSERVER(Observer, observers_, | 836 FOR_EACH_OBSERVER(Observer, observers_, |
| 827 OnCreatingAudioStream(render_process_id, render_frame_id)); | 837 OnCreatingAudioStream(render_process_id, render_frame_id)); |
| 828 } | 838 } |
| 829 | 839 |
| 830 bool MediaCaptureDevicesDispatcher::IsDesktopCaptureInProgress() { | 840 bool MediaCaptureDevicesDispatcher::IsDesktopCaptureInProgress() { |
| 831 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | 841 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
| 832 return desktop_capture_sessions_.size() > 0; | 842 return desktop_capture_sessions_.size() > 0; |
| 833 } | 843 } |
| OLD | NEW |