Index: chrome/browser/media/webrtc/media_stream_devices_controller.cc |
diff --git a/chrome/browser/media/webrtc/media_stream_devices_controller.cc b/chrome/browser/media/webrtc/media_stream_devices_controller.cc |
index e2ad13c5b49108a2c94bf2c0fde4c6f28db35df2..ea1c264f62b67e56e48482d26ceafad68e621440 100644 |
--- a/chrome/browser/media/webrtc/media_stream_devices_controller.cc |
+++ b/chrome/browser/media/webrtc/media_stream_devices_controller.cc |
@@ -173,8 +173,83 @@ class MediaPermissionRequestLogger : content::WebContentsObserver { |
RequestMap::key_type key_; |
}; |
+bool HasAvailableDevices(ContentSettingsType content_type, |
+ const std::string& device_id) { |
+ const content::MediaStreamDevices* devices = nullptr; |
+ if (content_type == CONTENT_SETTINGS_TYPE_MEDIASTREAM_MIC) { |
+ devices = |
+ &MediaCaptureDevicesDispatcher::GetInstance()->GetAudioCaptureDevices(); |
+ } else if (content_type == CONTENT_SETTINGS_TYPE_MEDIASTREAM_CAMERA) { |
+ devices = |
+ &MediaCaptureDevicesDispatcher::GetInstance()->GetVideoCaptureDevices(); |
+ } else { |
+ NOTREACHED(); |
+ } |
+ |
+ // TODO(tommi): It's kind of strange to have this here since if we fail this |
+ // test, there'll be a UI shown that indicates to the user that access to |
+ // non-existing audio/video devices has been denied. The user won't have |
+ // any way to change that but there will be a UI shown which indicates that |
+ // access is blocked. |
+ if (devices->empty()) |
+ return false; |
+ |
+ // Note: we check device_id before dereferencing devices. If the requested |
+ // device id is non-empty, then the corresponding device list must not be |
+ // NULL. |
+ if (!device_id.empty() && !devices->FindById(device_id)) |
+ return false; |
+ |
+ return true; |
+} |
+ |
} // namespace |
+// Stores whether a permission has been requested or blocked during the course |
+// of a permission request, as well as the denial reason |
+class MediaStreamDevicesController::MediaPermissionStatus { |
+ public: |
+ explicit MediaPermissionStatus(const content::MediaStreamRequest& request) |
+ : audio_requested_( |
+ ContentTypeIsRequested(CONTENT_SETTINGS_TYPE_MEDIASTREAM_MIC, |
+ request)), |
+ video_requested_( |
+ ContentTypeIsRequested(CONTENT_SETTINGS_TYPE_MEDIASTREAM_CAMERA, |
+ request)) {} |
+ |
+ ~MediaPermissionStatus() {} |
+ |
+ bool audio_requested() const { return audio_requested_; } |
+ bool video_requested() const { return video_requested_; } |
+ |
+ bool audio_blocked() const { return audio_blocked_; } |
+ bool video_blocked() const { return video_blocked_; } |
+ |
+ content::MediaStreamRequestResult denial_reason() const { |
+ return denial_reason_; |
+ } |
+ |
+ void SetAudioBlocked(content::MediaStreamRequestResult denial_reason) { |
+ DCHECK(audio_requested_); |
+ audio_blocked_ = true; |
+ denial_reason_ = denial_reason; |
+ } |
+ |
+ void SetVideoBlocked(content::MediaStreamRequestResult denial_reason) { |
+ DCHECK(video_requested_); |
+ video_blocked_ = true; |
+ denial_reason_ = denial_reason; |
+ } |
+ |
+ private: |
+ bool audio_requested_ = false; |
+ bool video_requested_ = false; |
+ bool audio_blocked_ = false; |
+ bool video_blocked_ = false; |
+ |
+ content::MediaStreamRequestResult denial_reason_ = content::MEDIA_DEVICE_OK; |
+}; |
+ |
// Implementation of PermissionPromptDelegate which actually shows a permission |
// prompt. |
class MediaStreamDevicesController::PermissionPromptDelegateImpl |
@@ -330,8 +405,28 @@ void MediaStreamDevicesController::RequestPermissionsWithDelegate( |
const content::MediaStreamRequest& request, |
const content::MediaResponseCallback& callback, |
PermissionPromptDelegate* delegate) { |
+ if (request.request_type == content::MEDIA_OPEN_DEVICE_PEPPER_ONLY) { |
+ MediaPermissionRequestLogger::LogRequest( |
+ web_contents, request.render_process_id, request.render_frame_id, |
+ content::IsOriginSecure(request.security_origin)); |
+ } |
+ |
+ MediaPermissionStatus initial_permission(request); |
+ if (initial_permission.audio_requested() && |
+ !HasAvailableDevices(CONTENT_SETTINGS_TYPE_MEDIASTREAM_MIC, |
+ request.requested_audio_device_id)) { |
+ initial_permission.SetAudioBlocked(content::MEDIA_DEVICE_NO_HARDWARE); |
+ } |
+ |
+ if (initial_permission.video_requested() && |
+ !HasAvailableDevices(CONTENT_SETTINGS_TYPE_MEDIASTREAM_CAMERA, |
+ request.requested_video_device_id)) { |
+ initial_permission.SetVideoBlocked(content::MEDIA_DEVICE_NO_HARDWARE); |
+ } |
+ |
std::unique_ptr<MediaStreamDevicesController> controller( |
- new MediaStreamDevicesController(web_contents, request, callback)); |
+ new MediaStreamDevicesController(web_contents, request, callback, |
+ initial_permission)); |
if (!controller->IsAskingForAudio() && !controller->IsAskingForVideo()) { |
#if defined(OS_ANDROID) |
// If either audio or video was previously allowed and Chrome no longer has |
@@ -363,21 +458,22 @@ void MediaStreamDevicesController::RequestPermissionsWithDelegate( |
MediaStreamDevicesController::MediaStreamDevicesController( |
content::WebContents* web_contents, |
const content::MediaStreamRequest& request, |
- const content::MediaResponseCallback& callback) |
+ const content::MediaResponseCallback& callback, |
+ const MediaPermissionStatus& initial_permission) |
: web_contents_(web_contents), request_(request), callback_(callback) { |
- if (request_.request_type == content::MEDIA_OPEN_DEVICE_PEPPER_ONLY) { |
- MediaPermissionRequestLogger::LogRequest( |
- web_contents, request.render_process_id, request.render_frame_id, |
- content::IsOriginSecure(request_.security_origin)); |
- } |
profile_ = Profile::FromBrowserContext(web_contents->GetBrowserContext()); |
content_settings_ = TabSpecificContentSettings::FromWebContents(web_contents); |
- content::MediaStreamRequestResult denial_reason = content::MEDIA_DEVICE_OK; |
- old_audio_setting_ = GetContentSetting(CONTENT_SETTINGS_TYPE_MEDIASTREAM_MIC, |
- request_, &denial_reason); |
- old_video_setting_ = GetContentSetting( |
- CONTENT_SETTINGS_TYPE_MEDIASTREAM_CAMERA, request_, &denial_reason); |
+ content::MediaStreamRequestResult denial_reason = |
+ initial_permission.denial_reason(); |
+ old_audio_setting_ = |
+ GetContentSetting(CONTENT_SETTINGS_TYPE_MEDIASTREAM_MIC, request, |
+ initial_permission.audio_requested(), |
+ initial_permission.audio_blocked(), &denial_reason); |
+ old_video_setting_ = |
+ GetContentSetting(CONTENT_SETTINGS_TYPE_MEDIASTREAM_CAMERA, request, |
+ initial_permission.video_requested(), |
+ initial_permission.video_blocked(), &denial_reason); |
// If either setting is ask, we show the infobar. |
if (old_audio_setting_ == CONTENT_SETTING_ASK || |
@@ -615,32 +711,32 @@ void MediaStreamDevicesController::UpdateTabSpecificContentSettings( |
ContentSetting MediaStreamDevicesController::GetContentSetting( |
ContentSettingsType content_type, |
const content::MediaStreamRequest& request, |
+ bool was_requested, |
+ bool was_initially_blocked, |
content::MediaStreamRequestResult* denial_reason) const { |
DCHECK(content_type == CONTENT_SETTINGS_TYPE_MEDIASTREAM_MIC || |
content_type == CONTENT_SETTINGS_TYPE_MEDIASTREAM_CAMERA); |
+ DCHECK(content::IsOriginSecure(request_.security_origin) || |
+ request_.request_type == content::MEDIA_OPEN_DEVICE_PEPPER_ONLY); |
+ if (!was_requested) { |
+ // No denial reason set as it will have been previously set. |
+ return CONTENT_SETTING_DEFAULT; |
+ } |
- std::string requested_device_id; |
- if (content_type == CONTENT_SETTINGS_TYPE_MEDIASTREAM_MIC) |
- requested_device_id = request.requested_audio_device_id; |
- else if (content_type == CONTENT_SETTINGS_TYPE_MEDIASTREAM_CAMERA) |
- requested_device_id = request.requested_video_device_id; |
+ if (was_initially_blocked) { |
+ // No denial reason set as it will have been previously set. |
+ return CONTENT_SETTING_BLOCK; |
+ } |
if (!IsUserAcceptAllowed(content_type)) { |
*denial_reason = content::MEDIA_DEVICE_PERMISSION_DENIED; |
return CONTENT_SETTING_BLOCK; |
} |
- if (ContentTypeIsRequested(content_type, request)) { |
- DCHECK(content::IsOriginSecure(request_.security_origin) || |
- request_.request_type == content::MEDIA_OPEN_DEVICE_PEPPER_ONLY); |
- MediaPermission permission(content_type, request.security_origin, |
- web_contents_->GetLastCommittedURL().GetOrigin(), |
- profile_, web_contents_); |
- return permission.GetPermissionStatusWithDeviceRequired(requested_device_id, |
- denial_reason); |
- } |
- // Return the default content setting if the device is not requested. |
- return CONTENT_SETTING_DEFAULT; |
+ MediaPermission permission(content_type, request.security_origin, |
+ web_contents_->GetLastCommittedURL().GetOrigin(), |
+ profile_, web_contents_); |
+ return permission.GetPermissionStatus(denial_reason); |
} |
ContentSetting MediaStreamDevicesController::GetNewSetting( |