Index: chrome/browser/media/media_capture_devices_dispatcher.cc |
diff --git a/chrome/browser/media/media_capture_devices_dispatcher.cc b/chrome/browser/media/media_capture_devices_dispatcher.cc |
index 4bfb4c9b75e67baa6562e8701bfd2f84fdc736ce..bcaeea3cfc433b7171aa23d1b2d2599073d24861 100644 |
--- a/chrome/browser/media/media_capture_devices_dispatcher.cc |
+++ b/chrome/browser/media/media_capture_devices_dispatcher.cc |
@@ -13,21 +13,17 @@ |
#include "base/strings/string_number_conversions.h" |
#include "base/strings/string_util.h" |
#include "base/strings/utf_string_conversions.h" |
+#include "chrome/browser/media/desktop_capture_access_handler.h" |
#include "chrome/browser/media/desktop_streams_registry.h" |
#include "chrome/browser/media/media_stream_capture_indicator.h" |
#include "chrome/browser/media/media_stream_device_permissions.h" |
-#include "chrome/browser/media/media_stream_infobar_delegate.h" |
-#include "chrome/browser/profiles/profile.h" |
+#include "chrome/browser/media/regular_media_access_handler.h" |
+#include "chrome/browser/media/tab_capture_access_handler.h" |
#include "chrome/browser/ui/browser.h" |
-#include "chrome/browser/ui/browser_finder.h" |
#include "chrome/browser/ui/browser_window.h" |
-#include "chrome/browser/ui/screen_capture_notification_ui.h" |
-#include "chrome/browser/ui/simple_message_box.h" |
-#include "chrome/browser/ui/website_settings/permission_bubble_manager.h" |
#include "chrome/common/chrome_switches.h" |
#include "chrome/common/chrome_version_info.h" |
#include "chrome/common/pref_names.h" |
-#include "chrome/grit/generated_resources.h" |
#include "components/content_settings/core/browser/host_content_settings_map.h" |
#include "components/pref_registry/pref_registry_syncable.h" |
#include "content/public/browser/browser_thread.h" |
@@ -41,20 +37,15 @@ |
#include "content/public/browser/web_contents.h" |
#include "content/public/common/media_stream_request.h" |
#include "extensions/common/constants.h" |
-#include "media/audio/audio_manager_base.h" |
#include "media/base/media_switches.h" |
#include "net/base/net_util.h" |
-#include "third_party/webrtc/modules/desktop_capture/desktop_capture_types.h" |
-#include "ui/base/l10n/l10n_util.h" |
#if defined(OS_CHROMEOS) |
#include "ash/shell.h" |
#endif // defined(OS_CHROMEOS) |
#if defined(ENABLE_EXTENSIONS) |
-#include "chrome/browser/extensions/api/tab_capture/tab_capture_registry.h" |
-#include "extensions/browser/app_window/app_window.h" |
-#include "extensions/browser/app_window/app_window_registry.h" |
+#include "chrome/browser/media/extension_media_access_handler.h" |
#include "extensions/browser/extension_registry.h" |
#include "extensions/common/extension.h" |
#include "extensions/common/permissions/permissions_data.h" |
@@ -66,16 +57,6 @@ using content::MediaStreamDevices; |
namespace { |
-// A finch experiment to enable the permission bubble for media requests only. |
-bool MediaStreamPermissionBubbleExperimentEnabled() { |
- const std::string group = |
- base::FieldTrialList::FindFullName("MediaStreamPermissionBubble"); |
- if (group == "enabled") |
- return true; |
- |
- return false; |
-} |
- |
// Finds a device in |devices| that has |device_id|, or NULL if not found. |
const content::MediaStreamDevice* FindDeviceWithId( |
const content::MediaStreamDevices& devices, |
@@ -110,130 +91,8 @@ bool IsMediaRequestWhitelistedForExtension( |
extension->id() == "jkghodnilhceideoidjikpgommlajknk" || |
extension->id() == "gjaehgfemfahhmlgpdfknkhdnemmolop"; |
} |
- |
-bool IsBuiltInExtension(const GURL& origin) { |
- return |
- // Feedback Extension. |
- origin.spec() == "chrome-extension://gfdkimpbcpahaombhbimeihdjnejgicl/"; |
-} |
- |
-// Returns true of the security origin is associated with casting. |
-bool IsOriginForCasting(const GURL& origin) { |
- // Whitelisted tab casting extensions. |
- return |
- // Dev |
- origin.spec() == "chrome-extension://enhhojjnijigcajfphajepfemndkmdlo/" || |
- // Canary |
- origin.spec() == "chrome-extension://hfaagokkkhdbgiakmmlclaapfelnkoah/" || |
- // Beta (internal) |
- origin.spec() == "chrome-extension://fmfcbgogabcbclcofgocippekhfcmgfj/" || |
- // Google Cast Beta |
- origin.spec() == "chrome-extension://dliochdbjfkdbacpmhlcpmleaejidimm/" || |
- // Google Cast Stable |
- origin.spec() == "chrome-extension://boadgeojelhgndaghljhdicfkmllpafd/" || |
- // http://crbug.com/457908 |
- origin.spec() == "chrome-extension://ekpaaapppgpmolpcldedioblbkmijaca/" || |
- origin.spec() == "chrome-extension://fjhoaacokmgbjemoflkofnenfaiekifl/"; |
-} |
- |
-bool IsExtensionWhitelistedForScreenCapture( |
- const extensions::Extension* extension) { |
-#if defined(OS_CHROMEOS) |
- std::string hash = base::SHA1HashString(extension->id()); |
- std::string hex_hash = base::HexEncode(hash.c_str(), hash.length()); |
- |
- // crbug.com/446688 |
- return hex_hash == "4F25792AF1AA7483936DE29C07806F203C7170A0" || |
- hex_hash == "BD8781D757D830FC2E85470A1B6E8A718B7EE0D9" || |
- hex_hash == "4AC2B6C63C6480D150DFDA13E4A5956EB1D0DDBB" || |
- hex_hash == "81986D4F846CEDDDB962643FA501D1780DD441BB"; |
-#else |
- return false; |
-#endif // defined(OS_CHROMEOS) |
-} |
#endif // defined(ENABLE_EXTENSIONS) |
-// Helper to get title of the calling application shown in the screen capture |
-// notification. |
-base::string16 GetApplicationTitle(content::WebContents* web_contents, |
- const extensions::Extension* extension) { |
- // Use extension name as title for extensions and host/origin for drive-by |
- // web. |
- std::string title; |
-#if defined(ENABLE_EXTENSIONS) |
- if (extension) { |
- title = extension->name(); |
- return base::UTF8ToUTF16(title); |
- } |
-#endif |
- GURL url = web_contents->GetURL(); |
- title = url.SchemeIsSecure() ? net::GetHostAndOptionalPort(url) |
- : url.GetOrigin().spec(); |
- return base::UTF8ToUTF16(title); |
-} |
- |
-// Helper to get list of media stream devices for desktop capture in |devices|. |
-// Registers to display notification if |display_notification| is true. |
-// Returns an instance of MediaStreamUI to be passed to content layer. |
-scoped_ptr<content::MediaStreamUI> GetDevicesForDesktopCapture( |
- content::MediaStreamDevices* devices, |
- content::DesktopMediaID media_id, |
- bool capture_audio, |
- bool display_notification, |
- const base::string16& application_title, |
- const base::string16& registered_extension_name) { |
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
- scoped_ptr<content::MediaStreamUI> ui; |
- |
- // Add selected desktop source to the list. |
- devices->push_back(content::MediaStreamDevice( |
- content::MEDIA_DESKTOP_VIDEO_CAPTURE, media_id.ToString(), "Screen")); |
- if (capture_audio) { |
- // Use the special loopback device ID for system audio capture. |
- devices->push_back(content::MediaStreamDevice( |
- content::MEDIA_DESKTOP_AUDIO_CAPTURE, |
- media::AudioManagerBase::kLoopbackInputDeviceId, "System Audio")); |
- } |
- |
- // If required, register to display the notification for stream capture. |
- if (display_notification) { |
- if (application_title == registered_extension_name) { |
- ui = ScreenCaptureNotificationUI::Create(l10n_util::GetStringFUTF16( |
- IDS_MEDIA_SCREEN_CAPTURE_NOTIFICATION_TEXT, |
- application_title)); |
- } else { |
- ui = ScreenCaptureNotificationUI::Create(l10n_util::GetStringFUTF16( |
- IDS_MEDIA_SCREEN_CAPTURE_NOTIFICATION_TEXT_DELEGATED, |
- registered_extension_name, |
- application_title)); |
- } |
- } |
- |
- return ui.Pass(); |
-} |
- |
-#if !defined(OS_ANDROID) |
-// Find browser or app window from a given |web_contents|. |
-gfx::NativeWindow FindParentWindowForWebContents( |
- content::WebContents* web_contents) { |
- Browser* browser = chrome::FindBrowserWithWebContents(web_contents); |
- if (browser && browser->window()) |
- return browser->window()->GetNativeWindow(); |
- |
- const extensions::AppWindowRegistry::AppWindowList& window_list = |
- extensions::AppWindowRegistry::Get( |
- web_contents->GetBrowserContext())->app_windows(); |
- for (extensions::AppWindowRegistry::AppWindowList::const_iterator iter = |
- window_list.begin(); |
- iter != window_list.end(); ++iter) { |
- if ((*iter)->web_contents() == web_contents) |
- return (*iter)->GetNativeWindow(); |
- } |
- |
- return NULL; |
-} |
-#endif |
- |
#if defined(ENABLE_EXTENSIONS) |
const extensions::Extension* GetExtensionForOrigin( |
Profile* profile, |
@@ -251,15 +110,6 @@ const extensions::Extension* GetExtensionForOrigin( |
} // namespace |
-MediaCaptureDevicesDispatcher::PendingAccessRequest::PendingAccessRequest( |
- const content::MediaStreamRequest& request, |
- const content::MediaResponseCallback& callback) |
- : request(request), |
- callback(callback) { |
-} |
- |
-MediaCaptureDevicesDispatcher::PendingAccessRequest::~PendingAccessRequest() {} |
- |
MediaCaptureDevicesDispatcher* MediaCaptureDevicesDispatcher::GetInstance() { |
return Singleton<MediaCaptureDevicesDispatcher>::get(); |
} |
@@ -350,26 +200,28 @@ void MediaCaptureDevicesDispatcher::ProcessMediaAccessRequest( |
if (request.video_type == content::MEDIA_DESKTOP_VIDEO_CAPTURE || |
Sergey Ulanov
2015/04/24 22:43:51
This code shouldn't need to know or care about typ
changbin
2015/04/29 05:24:34
This sounds better;)
Use list of MediaAccessHandl
|
request.audio_type == content::MEDIA_DESKTOP_AUDIO_CAPTURE) { |
- ProcessDesktopCaptureAccessRequest( |
- web_contents, request, callback, extension); |
+ media_access_handler_.reset( |
+ new DesktopCaptureAccessHandler(GetDesktopStreamsRegistry())); |
} else if (request.video_type == content::MEDIA_TAB_VIDEO_CAPTURE || |
request.audio_type == content::MEDIA_TAB_AUDIO_CAPTURE) { |
- ProcessTabCaptureAccessRequest( |
- web_contents, request, callback, extension); |
+ media_access_handler_.reset( |
+ new TabCaptureAccessHandler(media_stream_capture_indicator_)); |
} else { |
+ media_access_handler_.reset( |
Sergey Ulanov
2015/04/24 22:43:51
RegularMediaAccessHandler keeps queue of pending r
changbin
2015/04/29 05:24:34
That means it should pass pointer of RequestsQueue
Sergey Ulanov
2015/05/07 01:05:48
No. It means you shouldn't be reset handler for ev
|
+ new RegularMediaAccessHandler(pending_requests_)); |
#if defined(ENABLE_EXTENSIONS) |
bool is_whitelisted = |
extension && (extension->is_platform_app() || |
IsMediaRequestWhitelistedForExtension(extension)); |
if (is_whitelisted) { |
// For extensions access is approved based on extension permissions. |
- ProcessMediaAccessRequestFromPlatformAppOrExtension( |
- web_contents, request, callback, extension); |
- return; |
+ media_access_handler_.reset( |
+ new ExtensionMediaAccessHandler(media_stream_capture_indicator_)); |
} |
#endif |
- ProcessRegularMediaAccessRequest(web_contents, request, callback); |
} |
+ media_access_handler_->HandleRequest(web_contents, request, callback, |
+ extension); |
} |
bool MediaCaptureDevicesDispatcher::CheckMediaAccessPermission( |
@@ -497,426 +349,6 @@ bool MediaCaptureDevicesDispatcher::CheckMediaAccessPermission( |
} |
#endif |
-void MediaCaptureDevicesDispatcher::ProcessDesktopCaptureAccessRequest( |
- content::WebContents* web_contents, |
- const content::MediaStreamRequest& request, |
- const content::MediaResponseCallback& callback, |
- const extensions::Extension* extension) { |
- content::MediaStreamDevices devices; |
- scoped_ptr<content::MediaStreamUI> ui; |
- |
- if (request.video_type != content::MEDIA_DESKTOP_VIDEO_CAPTURE) { |
- callback.Run(devices, content::MEDIA_DEVICE_INVALID_STATE, ui.Pass()); |
- return; |
- } |
- |
- // If the device id wasn't specified then this is a screen capture request |
- // (i.e. chooseDesktopMedia() API wasn't used to generate device id). |
- if (request.requested_video_device_id.empty()) { |
- ProcessScreenCaptureAccessRequest( |
- web_contents, request, callback, extension); |
- return; |
- } |
- |
- // The extension name that the stream is registered with. |
- std::string original_extension_name; |
- // Resolve DesktopMediaID for the specified device id. |
- content::DesktopMediaID media_id; |
- // TODO(miu): Replace "main RenderFrame" IDs with the request's actual |
- // RenderFrame IDs once the desktop capture extension API implementation is |
- // fixed. http://crbug.com/304341 |
- content::WebContents* const web_contents_for_stream = |
- content::WebContents::FromRenderFrameHost( |
- content::RenderFrameHost::FromID(request.render_process_id, |
- request.render_frame_id)); |
- content::RenderFrameHost* const main_frame = web_contents_for_stream ? |
- web_contents_for_stream->GetMainFrame() : NULL; |
- if (main_frame) { |
- media_id = GetDesktopStreamsRegistry()->RequestMediaForStreamId( |
- request.requested_video_device_id, |
- main_frame->GetProcess()->GetID(), |
- main_frame->GetRoutingID(), |
- request.security_origin, |
- &original_extension_name); |
- } |
- |
- // Received invalid device id. |
- if (media_id.type == content::DesktopMediaID::TYPE_NONE) { |
- callback.Run(devices, content::MEDIA_DEVICE_INVALID_STATE, ui.Pass()); |
- return; |
- } |
- |
- bool loopback_audio_supported = false; |
-#if defined(USE_CRAS) || defined(OS_WIN) |
- // Currently loopback audio capture is supported only on Windows and ChromeOS. |
- loopback_audio_supported = true; |
-#endif |
- |
- // Audio is only supported for screen capture streams. |
- bool capture_audio = |
- (media_id.type == content::DesktopMediaID::TYPE_SCREEN && |
- request.audio_type == content::MEDIA_DESKTOP_AUDIO_CAPTURE && |
- loopback_audio_supported); |
- |
- ui = GetDevicesForDesktopCapture( |
- &devices, media_id, capture_audio, true, |
- GetApplicationTitle(web_contents, extension), |
- base::UTF8ToUTF16(original_extension_name)); |
- |
- callback.Run(devices, content::MEDIA_DEVICE_OK, ui.Pass()); |
-} |
- |
-void MediaCaptureDevicesDispatcher::ProcessScreenCaptureAccessRequest( |
- content::WebContents* web_contents, |
- const content::MediaStreamRequest& request, |
- const content::MediaResponseCallback& callback, |
- const extensions::Extension* extension) { |
- content::MediaStreamDevices devices; |
- scoped_ptr<content::MediaStreamUI> ui; |
- |
- DCHECK_EQ(request.video_type, content::MEDIA_DESKTOP_VIDEO_CAPTURE); |
- |
- bool loopback_audio_supported = false; |
-#if defined(USE_CRAS) || defined(OS_WIN) |
- // Currently loopback audio capture is supported only on Windows and ChromeOS. |
- loopback_audio_supported = true; |
-#endif |
- |
- bool component_extension = false; |
-#if defined(ENABLE_EXTENSIONS) |
- component_extension = |
- extension && extension->location() == extensions::Manifest::COMPONENT; |
-#endif |
- |
- bool screen_capture_enabled = |
- base::CommandLine::ForCurrentProcess()->HasSwitch( |
- switches::kEnableUserMediaScreenCapturing); |
-#if defined(ENABLE_EXTENSIONS) |
- screen_capture_enabled |= |
- IsOriginForCasting(request.security_origin) || |
- IsExtensionWhitelistedForScreenCapture(extension) || |
- IsBuiltInExtension(request.security_origin); |
-#endif |
- |
- const bool origin_is_secure = |
- request.security_origin.SchemeIsSecure() || |
- request.security_origin.SchemeIs(extensions::kExtensionScheme) || |
- base::CommandLine::ForCurrentProcess()->HasSwitch( |
- switches::kAllowHttpScreenCapture); |
- |
- // If basic conditions (screen capturing is enabled and origin is secure) |
- // aren't fulfilled, we'll use "invalid state" as result. Otherwise, we set |
- // it after checking permission. |
- // TODO(grunell): It would be good to change this result for something else, |
- // probably a new one. |
- content::MediaStreamRequestResult result = |
- content::MEDIA_DEVICE_INVALID_STATE; |
- |
- // Approve request only when the following conditions are met: |
- // 1. Screen capturing is enabled via command line switch or white-listed for |
- // the given origin. |
- // 2. Request comes from a page with a secure origin or from an extension. |
- if (screen_capture_enabled && origin_is_secure) { |
- // Get title of the calling application prior to showing the message box. |
- // chrome::ShowMessageBox() starts a nested message loop which may allow |
- // |web_contents| to be destroyed on the UI thread before the message box |
- // is closed. See http://crbug.com/326690. |
- base::string16 application_title = |
- GetApplicationTitle(web_contents, extension); |
-#if !defined(OS_ANDROID) |
- gfx::NativeWindow parent_window = |
- FindParentWindowForWebContents(web_contents); |
-#else |
- gfx::NativeWindow parent_window = NULL; |
-#endif |
- web_contents = NULL; |
- |
- bool whitelisted_extension = false; |
-#if defined(ENABLE_EXTENSIONS) |
- whitelisted_extension = IsExtensionWhitelistedForScreenCapture( |
- extension); |
-#endif |
- |
- // For whitelisted or component extensions, bypass message box. |
- bool user_approved = false; |
- if (!whitelisted_extension && !component_extension) { |
- base::string16 application_name = |
- base::UTF8ToUTF16(request.security_origin.spec()); |
-#if defined(ENABLE_EXTENSIONS) |
- if (extension) |
- application_name = base::UTF8ToUTF16(extension->name()); |
-#endif |
- base::string16 confirmation_text = l10n_util::GetStringFUTF16( |
- request.audio_type == content::MEDIA_NO_SERVICE ? |
- IDS_MEDIA_SCREEN_CAPTURE_CONFIRMATION_TEXT : |
- IDS_MEDIA_SCREEN_AND_AUDIO_CAPTURE_CONFIRMATION_TEXT, |
- application_name); |
- chrome::MessageBoxResult result = chrome::ShowMessageBox( |
- parent_window, |
- l10n_util::GetStringFUTF16( |
- IDS_MEDIA_SCREEN_CAPTURE_CONFIRMATION_TITLE, application_name), |
- confirmation_text, |
- chrome::MESSAGE_BOX_TYPE_QUESTION); |
- user_approved = (result == chrome::MESSAGE_BOX_RESULT_YES); |
- } |
- |
- if (user_approved || component_extension || whitelisted_extension) { |
- content::DesktopMediaID screen_id; |
-#if defined(OS_CHROMEOS) |
- screen_id = content::DesktopMediaID::RegisterAuraWindow( |
- ash::Shell::GetInstance()->GetPrimaryRootWindow()); |
-#else // defined(OS_CHROMEOS) |
- screen_id = |
- content::DesktopMediaID(content::DesktopMediaID::TYPE_SCREEN, |
- webrtc::kFullDesktopScreenId); |
-#endif // !defined(OS_CHROMEOS) |
- |
- bool capture_audio = |
- (request.audio_type == content::MEDIA_DESKTOP_AUDIO_CAPTURE && |
- loopback_audio_supported); |
- |
- // Unless we're being invoked from a component extension, register to |
- // display the notification for stream capture. |
- bool display_notification = !component_extension; |
- |
- ui = GetDevicesForDesktopCapture(&devices, screen_id, capture_audio, |
- display_notification, application_title, |
- application_title); |
- DCHECK(!devices.empty()); |
- } |
- |
- // The only case when devices can be empty is if the user has denied |
- // permission. |
- result = devices.empty() ? content::MEDIA_DEVICE_PERMISSION_DENIED |
- : content::MEDIA_DEVICE_OK; |
- } |
- |
- callback.Run(devices, result, ui.Pass()); |
-} |
- |
-void MediaCaptureDevicesDispatcher::ProcessTabCaptureAccessRequest( |
- content::WebContents* web_contents, |
- const content::MediaStreamRequest& request, |
- const content::MediaResponseCallback& callback, |
- const extensions::Extension* extension) { |
- content::MediaStreamDevices devices; |
- scoped_ptr<content::MediaStreamUI> ui; |
- |
-#if defined(ENABLE_EXTENSIONS) |
- Profile* profile = |
- Profile::FromBrowserContext(web_contents->GetBrowserContext()); |
- extensions::TabCaptureRegistry* tab_capture_registry = |
- extensions::TabCaptureRegistry::Get(profile); |
- if (!tab_capture_registry) { |
- NOTREACHED(); |
- callback.Run(devices, content::MEDIA_DEVICE_INVALID_STATE, ui.Pass()); |
- return; |
- } |
- const bool tab_capture_allowed = tab_capture_registry->VerifyRequest( |
- request.render_process_id, request.render_frame_id, extension->id()); |
- |
- if (request.audio_type == content::MEDIA_TAB_AUDIO_CAPTURE && |
- tab_capture_allowed && |
- extension->permissions_data()->HasAPIPermission( |
- extensions::APIPermission::kTabCapture)) { |
- devices.push_back(content::MediaStreamDevice( |
- content::MEDIA_TAB_AUDIO_CAPTURE, std::string(), std::string())); |
- } |
- |
- if (request.video_type == content::MEDIA_TAB_VIDEO_CAPTURE && |
- tab_capture_allowed && |
- extension->permissions_data()->HasAPIPermission( |
- extensions::APIPermission::kTabCapture)) { |
- devices.push_back(content::MediaStreamDevice( |
- content::MEDIA_TAB_VIDEO_CAPTURE, std::string(), std::string())); |
- } |
- |
- if (!devices.empty()) { |
- ui = media_stream_capture_indicator_->RegisterMediaStream( |
- web_contents, devices); |
- } |
- callback.Run( |
- devices, |
- devices.empty() ? content::MEDIA_DEVICE_INVALID_STATE : |
- content::MEDIA_DEVICE_OK, |
- ui.Pass()); |
-#else // defined(ENABLE_EXTENSIONS) |
- callback.Run(devices, content::MEDIA_DEVICE_TAB_CAPTURE_FAILURE, ui.Pass()); |
-#endif // defined(ENABLE_EXTENSIONS) |
-} |
- |
-#if defined(ENABLE_EXTENSIONS) |
-void MediaCaptureDevicesDispatcher:: |
- ProcessMediaAccessRequestFromPlatformAppOrExtension( |
- content::WebContents* web_contents, |
- const content::MediaStreamRequest& request, |
- const content::MediaResponseCallback& callback, |
- const extensions::Extension* extension) { |
- // TODO(vrk): This code is largely duplicated in |
- // MediaStreamDevicesController::Accept(). Move this code into a shared method |
- // between the two classes. |
- |
- Profile* profile = |
- Profile::FromBrowserContext(web_contents->GetBrowserContext()); |
- |
- bool audio_allowed = |
- request.audio_type == content::MEDIA_DEVICE_AUDIO_CAPTURE && |
- extension->permissions_data()->HasAPIPermission( |
- extensions::APIPermission::kAudioCapture) && |
- GetDevicePolicy(profile, extension->url(), |
- prefs::kAudioCaptureAllowed, |
- prefs::kAudioCaptureAllowedUrls) != ALWAYS_DENY; |
- bool video_allowed = |
- request.video_type == content::MEDIA_DEVICE_VIDEO_CAPTURE && |
- extension->permissions_data()->HasAPIPermission( |
- extensions::APIPermission::kVideoCapture) && |
- GetDevicePolicy(profile, extension->url(), |
- prefs::kVideoCaptureAllowed, |
- prefs::kVideoCaptureAllowedUrls) != ALWAYS_DENY; |
- |
- bool get_default_audio_device = audio_allowed; |
- bool get_default_video_device = video_allowed; |
- |
- content::MediaStreamDevices devices; |
- |
- // Set an initial error result. If neither audio or video is allowed, we'll |
- // never try to get any device below but will just create |ui| and return an |
- // empty list with "invalid state" result. If at least one is allowed, we'll |
- // try to get device(s), and if failure, we want to return "no hardware" |
- // result. |
- // TODO(grunell): The invalid state result should be changed to a new denied |
- // result + a dcheck to ensure at least one of audio or video types is |
- // capture. |
- content::MediaStreamRequestResult result = |
- (audio_allowed || video_allowed) ? content::MEDIA_DEVICE_NO_HARDWARE |
- : content::MEDIA_DEVICE_INVALID_STATE; |
- |
- // Get the exact audio or video device if an id is specified. |
- // We only set any error result here and before running the callback change |
- // it to OK if we have any device. |
- if (audio_allowed && !request.requested_audio_device_id.empty()) { |
- const content::MediaStreamDevice* audio_device = |
- GetRequestedAudioDevice(request.requested_audio_device_id); |
- if (audio_device) { |
- devices.push_back(*audio_device); |
- get_default_audio_device = false; |
- } |
- } |
- if (video_allowed && !request.requested_video_device_id.empty()) { |
- const content::MediaStreamDevice* video_device = |
- GetRequestedVideoDevice(request.requested_video_device_id); |
- if (video_device) { |
- devices.push_back(*video_device); |
- get_default_video_device = false; |
- } |
- } |
- |
- // If either or both audio and video devices were requested but not |
- // specified by id, get the default devices. |
- if (get_default_audio_device || get_default_video_device) { |
- GetDefaultDevicesForProfile(profile, |
- get_default_audio_device, |
- get_default_video_device, |
- &devices); |
- } |
- |
- scoped_ptr<content::MediaStreamUI> ui; |
- if (!devices.empty()) { |
- result = content::MEDIA_DEVICE_OK; |
- ui = media_stream_capture_indicator_->RegisterMediaStream( |
- web_contents, devices); |
- } |
- |
- callback.Run(devices, result, ui.Pass()); |
-} |
-#endif |
- |
-void MediaCaptureDevicesDispatcher::ProcessRegularMediaAccessRequest( |
- content::WebContents* web_contents, |
- const content::MediaStreamRequest& request, |
- const content::MediaResponseCallback& callback) { |
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
- |
- RequestsQueue& queue = pending_requests_[web_contents]; |
- queue.push_back(PendingAccessRequest(request, callback)); |
- |
- // If this is the only request then show the infobar. |
- if (queue.size() == 1) |
- ProcessQueuedAccessRequest(web_contents); |
-} |
- |
-void MediaCaptureDevicesDispatcher::ProcessQueuedAccessRequest( |
- content::WebContents* web_contents) { |
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
- |
- std::map<content::WebContents*, RequestsQueue>::iterator it = |
- pending_requests_.find(web_contents); |
- |
- if (it == pending_requests_.end() || it->second.empty()) { |
- // Don't do anything if the tab was closed. |
- return; |
- } |
- |
- DCHECK(!it->second.empty()); |
- |
- if (PermissionBubbleManager::Enabled() || |
- MediaStreamPermissionBubbleExperimentEnabled()) { |
- scoped_ptr<MediaStreamDevicesController> controller( |
- new MediaStreamDevicesController(web_contents, |
- it->second.front().request, |
- base::Bind(&MediaCaptureDevicesDispatcher::OnAccessRequestResponse, |
- base::Unretained(this), web_contents))); |
- if (controller->DismissInfoBarAndTakeActionOnSettings()) |
- return; |
- PermissionBubbleManager* bubble_manager = |
- PermissionBubbleManager::FromWebContents(web_contents); |
- if (bubble_manager) |
- bubble_manager->AddRequest(controller.release()); |
- return; |
- } |
- |
- // TODO(gbillock): delete this block and the MediaStreamInfoBarDelegate |
- // when we've transitioned to bubbles. (crbug/337458) |
- MediaStreamInfoBarDelegate::Create( |
- web_contents, it->second.front().request, |
- base::Bind(&MediaCaptureDevicesDispatcher::OnAccessRequestResponse, |
- base::Unretained(this), web_contents)); |
-} |
- |
-void MediaCaptureDevicesDispatcher::OnAccessRequestResponse( |
- content::WebContents* web_contents, |
- const content::MediaStreamDevices& devices, |
- content::MediaStreamRequestResult result, |
- scoped_ptr<content::MediaStreamUI> ui) { |
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
- |
- std::map<content::WebContents*, RequestsQueue>::iterator it = |
- pending_requests_.find(web_contents); |
- if (it == pending_requests_.end()) { |
- // WebContents has been destroyed. Don't need to do anything. |
- return; |
- } |
- |
- RequestsQueue& queue(it->second); |
- if (queue.empty()) |
- return; |
- |
- content::MediaResponseCallback callback = queue.front().callback; |
- queue.pop_front(); |
- |
- if (!queue.empty()) { |
- // Post a task to process next queued request. It has to be done |
- // asynchronously to make sure that calling infobar is not destroyed until |
- // after this function returns. |
- BrowserThread::PostTask( |
- BrowserThread::UI, FROM_HERE, |
- base::Bind(&MediaCaptureDevicesDispatcher::ProcessQueuedAccessRequest, |
- base::Unretained(this), web_contents)); |
- } |
- |
- callback.Run(devices, result, ui.Pass()); |
-} |
- |
void MediaCaptureDevicesDispatcher::GetDefaultDevicesForProfile( |
Profile* profile, |
bool audio, |