Diff
Modified: trunk/LayoutTests/ChangeLog (237769 => 237770)
--- trunk/LayoutTests/ChangeLog 2018-11-03 06:25:56 UTC (rev 237769)
+++ trunk/LayoutTests/ChangeLog 2018-11-03 13:30:30 UTC (rev 237770)
@@ -1,3 +1,17 @@
+2018-11-03 Eric Carlson <[email protected]>
+
+ [MediaStream] enumerateDevices should not expose devices that are not available to getUserMedia
+ https://bugs.webkit.org/show_bug.cgi?id=191177
+ <rdar://problem/45747873>
+
+ Reviewed by Jer Noble.
+
+ * http/tests/media/media-stream/enumerate-devices-iframe-allow-attribute-expected.txt: Added.
+ * http/tests/media/media-stream/enumerate-devices-iframe-allow-attribute.html: Added.
+ * http/tests/media/media-stream/resources/enumerate-devices-iframe.html: Added.
+ * http/tests/ssl/media-stream/get-user-media-different-host-expected.txt: Rebased for updated logging.
+ * http/tests/ssl/media-stream/get-user-media-nested-expected.txt: Ditto.
+
2018-11-02 Justin Michaud <[email protected]>
Add new global object and preliminary Worklets support for CSS painting api
Added: trunk/LayoutTests/http/tests/media/media-stream/enumerate-devices-iframe-allow-attribute-expected.txt (0 => 237770)
--- trunk/LayoutTests/http/tests/media/media-stream/enumerate-devices-iframe-allow-attribute-expected.txt (rev 0)
+++ trunk/LayoutTests/http/tests/media/media-stream/enumerate-devices-iframe-allow-attribute-expected.txt 2018-11-03 13:30:30 UTC (rev 237770)
@@ -0,0 +1,3 @@
+CONSOLE MESSAGE: line 4: The top-level frame has prevented a document with a different security origin from calling enumerateDevices.
+
+PASS: "allow" attribute respected in all iframes
Added: trunk/LayoutTests/http/tests/media/media-stream/enumerate-devices-iframe-allow-attribute.html (0 => 237770)
--- trunk/LayoutTests/http/tests/media/media-stream/enumerate-devices-iframe-allow-attribute.html (rev 0)
+++ trunk/LayoutTests/http/tests/media/media-stream/enumerate-devices-iframe-allow-attribute.html 2018-11-03 13:30:30 UTC (rev 237770)
@@ -0,0 +1,49 @@
+<!doctype html>
+<html>
+<script src=""
+<body>
+ <iframe id=none src=""
+ <iframe id="microphone" allow="microphone" src=""
+ <iframe id="camera" allow="camera" src=""
+ <iframe id="camera+microphone" allow="camera;microphone" src=""
+ <iframe id="same-origin" src=""
+
+ <script>
+
+ if (window.testRunner) {
+ testRunner.dumpAsText();
+ testRunner.waitUntilDone();
+ testRunner.setUserMediaPermission(true);
+ }
+
+ let expected = {
+ 'microphone' : 'microphone',
+ 'none' : '',
+ 'camera+microphone' : 'camera+microphone',
+ 'camera' : 'camera',
+ 'same-origin' : 'camera+microphone'
+ };
+ let count = 0;
+ let success = true;
+ window.addEventListener("message", (event) => {
+ let visible = event.data.trim().split(':');
+ if (expected[visible[0]] != visible[1]) {
+ result.innerHTML += `FAIL: <iframe id=${visible[0]}> saw "${visible[1]}", should have seen "${expected[visible[0]]}"<br>`;
+ success = false;
+ }
+ if (++count == 5) {
+ if (success)
+ result.innerHTML = 'PASS: "allow" attribute respected in all iframes';
+ if (window.testRunner)
+ testRunner.notifyDone();
+ }
+
+ }, false);
+
+ let enumerate = (evt) => { evt.target.contentWindow.postMessage(evt.target.id, '*'); }
+ Array.from(document.getElementsByTagName('iframe')).forEach(element => element._onload_ = enumerate);
+ </script>
+
+ <div id="result"></div>
+</body>
+</html>
Added: trunk/LayoutTests/http/tests/media/media-stream/resources/enumerate-devices-iframe.html (0 => 237770)
--- trunk/LayoutTests/http/tests/media/media-stream/resources/enumerate-devices-iframe.html (rev 0)
+++ trunk/LayoutTests/http/tests/media/media-stream/resources/enumerate-devices-iframe.html 2018-11-03 13:30:30 UTC (rev 237770)
@@ -0,0 +1,16 @@
+<script>
+ async function enumerate(event)
+ {
+ let devices = await navigator.mediaDevices.enumerateDevices();
+ let visible = devices.map(device => device.kind.indexOf('video') == 0 ? 'camera' : 'microphone').sort();
+ visible = visible.join('+');
+ parent.postMessage(`${event.data}:${visible}`, '*');
+ result.innerHTML = visible;
+ }
+
+ window.addEventListener("message", (id) => enumerate(id));
+</script>
+
+<div id='result'></div>
+
+
Modified: trunk/LayoutTests/http/tests/ssl/media-stream/get-user-media-different-host-expected.txt (237769 => 237770)
--- trunk/LayoutTests/http/tests/ssl/media-stream/get-user-media-different-host-expected.txt 2018-11-03 06:25:56 UTC (rev 237769)
+++ trunk/LayoutTests/http/tests/ssl/media-stream/get-user-media-different-host-expected.txt 2018-11-03 13:30:30 UTC (rev 237770)
@@ -1,4 +1,4 @@
-CONSOLE MESSAGE: line 52: The top-level frame has prevented a document with a different security origin to call getUserMedia.
+CONSOLE MESSAGE: line 52: The top-level frame has prevented a document with a different security origin from calling getUserMedia.
Tests that getUserMedia fails when the top level document and iframe do not have the same domain.
On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
Modified: trunk/LayoutTests/http/tests/ssl/media-stream/get-user-media-nested-expected.txt (237769 => 237770)
--- trunk/LayoutTests/http/tests/ssl/media-stream/get-user-media-nested-expected.txt 2018-11-03 06:25:56 UTC (rev 237769)
+++ trunk/LayoutTests/http/tests/ssl/media-stream/get-user-media-nested-expected.txt 2018-11-03 13:30:30 UTC (rev 237770)
@@ -1,4 +1,4 @@
-CONSOLE MESSAGE: line 52: The top-level frame has prevented a document with a different security origin to call getUserMedia.
+CONSOLE MESSAGE: line 52: The top-level frame has prevented a document with a different security origin from calling getUserMedia.
Tests that getUserMedia fails when the top level document and iframe do not have the same domain.
On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
Modified: trunk/LayoutTests/imported/w3c/web-platform-tests/mediacapture-streams/MediaStream-default-feature-policy.https-expected.txt (237769 => 237770)
--- trunk/LayoutTests/imported/w3c/web-platform-tests/mediacapture-streams/MediaStream-default-feature-policy.https-expected.txt 2018-11-03 06:25:56 UTC (rev 237769)
+++ trunk/LayoutTests/imported/w3c/web-platform-tests/mediacapture-streams/MediaStream-default-feature-policy.https-expected.txt 2018-11-03 13:30:30 UTC (rev 237770)
@@ -1,10 +1,10 @@
-CONSOLE MESSAGE: line 16: The top-level frame has prevented a document with a different security origin to call getUserMedia.
-CONSOLE MESSAGE: line 16: The top-level frame has prevented a document with a different security origin to call getUserMedia.
-CONSOLE MESSAGE: line 16: The top-level frame has prevented a document with a different security origin to call getUserMedia.
-CONSOLE MESSAGE: line 16: The top-level frame has prevented a document with a different security origin to call getUserMedia.
-CONSOLE MESSAGE: line 16: The top-level frame has prevented a document with a different security origin to call getUserMedia.
-CONSOLE MESSAGE: line 16: The top-level frame has prevented a document with a different security origin to call getUserMedia.
-CONSOLE MESSAGE: line 16: The top-level frame has prevented a document with a different security origin to call getUserMedia.
+CONSOLE MESSAGE: line 16: The top-level frame has prevented a document with a different security origin from calling getUserMedia.
+CONSOLE MESSAGE: line 16: The top-level frame has prevented a document with a different security origin from calling getUserMedia.
+CONSOLE MESSAGE: line 16: The top-level frame has prevented a document with a different security origin from calling getUserMedia.
+CONSOLE MESSAGE: line 16: The top-level frame has prevented a document with a different security origin from calling getUserMedia.
+CONSOLE MESSAGE: line 16: The top-level frame has prevented a document with a different security origin from calling getUserMedia.
+CONSOLE MESSAGE: line 16: The top-level frame has prevented a document with a different security origin from calling getUserMedia.
+CONSOLE MESSAGE: line 16: The top-level frame has prevented a document with a different security origin from calling getUserMedia.
PASS Default "microphone" feature policy ["self"] allows the top-level document.
Modified: trunk/Source/WebCore/ChangeLog (237769 => 237770)
--- trunk/Source/WebCore/ChangeLog 2018-11-03 06:25:56 UTC (rev 237769)
+++ trunk/Source/WebCore/ChangeLog 2018-11-03 13:30:30 UTC (rev 237770)
@@ -1,3 +1,29 @@
+2018-11-03 Eric Carlson <[email protected]>
+
+ [MediaStream] enumerateDevices should not expose devices that are not available to getUserMedia
+ https://bugs.webkit.org/show_bug.cgi?id=191177
+ <rdar://problem/45747873>
+
+ Reviewed by Jer Noble.
+
+ Test: http/tests/media/media-stream/enumerate-devices-iframe-allow-attribute.html
+
+ * Modules/mediastream/MediaDevicesRequest.cpp:
+ (WebCore::MediaDevicesRequest::start): Only expose devices that are available to gUM.
+
+ * Modules/mediastream/UserMediaController.cpp:
+ (WebCore::isSecure): Moved from UserMediaRequest.cpp.
+ (WebCore::isAllowedToUse): Ditto.
+ (WebCore::UserMediaController::canCallGetUserMedia): Modified from UserMediaRequest.cpp.
+ (WebCore::UserMediaController::logGetUserMediaDenial): Log reason for denial.
+ * Modules/mediastream/UserMediaController.h:
+
+ * Modules/mediastream/UserMediaRequest.cpp:
+ (WebCore::UserMediaRequest::start): Use UserMediaController::canCallGetUserMedia.
+ (WebCore::isSecure): Deleted.
+ (WebCore::isAllowedToUse): Deleted.
+ (WebCore::canCallGetUserMedia): Deleted.
+
2018-11-02 Justin Michaud <[email protected]>
Add new global object and preliminary Worklets support for CSS painting api
Modified: trunk/Source/WebCore/Modules/mediastream/MediaDevicesRequest.cpp (237769 => 237770)
--- trunk/Source/WebCore/Modules/mediastream/MediaDevicesRequest.cpp 2018-11-03 06:25:56 UTC (rev 237769)
+++ trunk/Source/WebCore/Modules/mediastream/MediaDevicesRequest.cpp 2018-11-03 13:30:30 UTC (rev 237770)
@@ -103,8 +103,31 @@
void MediaDevicesRequest::start()
{
+ auto& document = downcast<Document>(*scriptExecutionContext());
+ auto* controller = UserMediaController::from(document.page());
+ if (!controller) {
+ callOnMainThread([protectedThis = makeRef(*this)]() {
+ protectedThis->m_promise.resolve({ });
+ });
+
+ return;
+ }
+
+ auto microphoneAccess = controller->canCallGetUserMedia(document, true, false);
+ auto cameraAccess = controller->canCallGetUserMedia(document, false, true);
+ bool canAccessMicrophone = microphoneAccess == UserMediaController::GetUserMediaAccess::CanCall;
+ bool canAccessCamera = cameraAccess == UserMediaController::GetUserMediaAccess::CanCall;
+ if (!canAccessMicrophone && !canAccessCamera) {
+ controller->logGetUserMediaDenial(document, !canAccessMicrophone ? microphoneAccess : cameraAccess, UserMediaController::BlockedCaller::EnumerateDevices);
+ callOnMainThread([protectedThis = makeRef(*this)]() {
+ protectedThis->m_promise.resolve({ });
+ });
+
+ return;
+ }
+
// This lambda keeps |this| alive until the request completes or is canceled.
- auto completion = [this, protectedThis = makeRef(*this)] (const Vector<CaptureDevice>& captureDevices, const String& deviceIdentifierHashSalt, bool originHasPersistentAccess) mutable {
+ auto completion = [this, protectedThis = makeRef(*this), canAccessMicrophone, canAccessCamera] (const Vector<CaptureDevice>& captureDevices, const String& deviceIdentifierHashSalt, bool originHasPersistentAccess) mutable {
m_enumerationRequest = nullptr;
@@ -117,6 +140,11 @@
Vector<Ref<MediaDeviceInfo>> devices;
bool revealIdsAndLabels = originHasPersistentAccess || document.hasHadCaptureMediaStreamTrack();
for (auto& deviceInfo : captureDevices) {
+ if (!canAccessMicrophone && deviceInfo.type() == CaptureDevice::DeviceType::Microphone)
+ continue;
+ if (!canAccessCamera && deviceInfo.type() == CaptureDevice::DeviceType::Camera)
+ continue;
+
auto label = emptyString();
auto id = emptyString();
auto groupId = emptyString();
@@ -140,7 +168,7 @@
});
};
- m_enumerationRequest = MediaDevicesEnumerationRequest::create(*downcast<Document>(scriptExecutionContext()), WTFMove(completion));
+ m_enumerationRequest = MediaDevicesEnumerationRequest::create(document, WTFMove(completion));
m_enumerationRequest->start();
}
Modified: trunk/Source/WebCore/Modules/mediastream/UserMediaController.cpp (237769 => 237770)
--- trunk/Source/WebCore/Modules/mediastream/UserMediaController.cpp 2018-11-03 06:25:56 UTC (rev 237769)
+++ trunk/Source/WebCore/Modules/mediastream/UserMediaController.cpp 2018-11-03 13:30:30 UTC (rev 237770)
@@ -1,5 +1,6 @@
/*
* Copyright (C) 2012 Google Inc. All rights reserved.
+ * Copyright (C) 2013-2018 Apple Inc. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
@@ -27,6 +28,14 @@
#if ENABLE(MEDIA_STREAM)
+#include "DOMWindow.h"
+#include "DeprecatedGlobalSettings.h"
+#include "Document.h"
+#include "DocumentLoader.h"
+#include "Frame.h"
+#include "HTMLIFrameElement.h"
+#include "HTMLParserIdioms.h"
+#include "SchemeRegistry.h"
#include "UserMediaRequest.h"
namespace WebCore {
@@ -51,6 +60,91 @@
UserMediaController::provideTo(page, UserMediaController::supplementName(), std::make_unique<UserMediaController>(client));
}
+static bool isSecure(DocumentLoader& documentLoader)
+{
+ auto& response = documentLoader.response();
+ if (SecurityOrigin::isLocalHostOrLoopbackIPAddress(documentLoader.response().url().host()))
+ return true;
+ return SchemeRegistry::shouldTreatURLSchemeAsSecure(response.url().protocol().toStringWithoutCopying())
+ && response.certificateInfo()
+ && !response.certificateInfo()->containsNonRootSHA1SignedCertificate();
+}
+
+static bool isAllowedToUse(Document& document, Document& topDocument, bool requiresAudio, bool requiresVideo)
+{
+ if (&document == &topDocument)
+ return true;
+
+ auto* parentDocument = document.parentDocument();
+ if (!parentDocument)
+ return false;
+
+ if (document.securityOrigin().isSameSchemeHostPort(parentDocument->securityOrigin()))
+ return true;
+
+ auto* element = document.ownerElement();
+ ASSERT(element);
+ if (!element)
+ return false;
+
+ if (!is<HTMLIFrameElement>(*element))
+ return false;
+ auto& allow = downcast<HTMLIFrameElement>(*element).allow();
+
+ bool allowCameraAccess = false;
+ bool allowMicrophoneAccess = false;
+ for (auto allowItem : StringView { allow }.split(';')) {
+ auto item = allowItem.stripLeadingAndTrailingMatchedCharacters(isHTMLSpace<UChar>);
+ if (!allowCameraAccess && item == "camera")
+ allowCameraAccess = true;
+ else if (!allowMicrophoneAccess && item == "microphone")
+ allowMicrophoneAccess = true;
+ }
+ return (allowCameraAccess || !requiresVideo) && (allowMicrophoneAccess || !requiresAudio);
+}
+
+UserMediaController::GetUserMediaAccess UserMediaController::canCallGetUserMedia(Document& document, bool wantsAudio, bool wantsVideo)
+{
+ ASSERT(wantsAudio || wantsVideo);
+
+ bool requiresSecureConnection = DeprecatedGlobalSettings::mediaCaptureRequiresSecureConnection();
+ auto& documentLoader = *document.loader();
+ if (requiresSecureConnection && !isSecure(documentLoader))
+ return GetUserMediaAccess::InsecureDocument;
+
+ auto& topDocument = document.topDocument();
+ if (&document != &topDocument) {
+ for (auto* ancestorDocument = &document; ancestorDocument != &topDocument; ancestorDocument = ancestorDocument->parentDocument()) {
+ if (requiresSecureConnection && !isSecure(*ancestorDocument->loader()))
+ return GetUserMediaAccess::InsecureParent;
+
+ if (!isAllowedToUse(*ancestorDocument, topDocument, wantsAudio, wantsVideo))
+ return GetUserMediaAccess::BlockedByParent;
+ }
+ }
+
+ return GetUserMediaAccess::CanCall;
+}
+
+void UserMediaController::logGetUserMediaDenial(Document& document, GetUserMediaAccess access, BlockedCaller caller)
+{
+ auto& domWindow = *document.domWindow();
+ const char* callerName = caller == BlockedCaller::GetUserMedia ? "getUserMedia" : "enumerateDevices";
+ switch (access) {
+ case UserMediaController::GetUserMediaAccess::InsecureDocument:
+ domWindow.printErrorMessage(makeString("Trying to call ", callerName, " from an insecure document."));
+ break;
+ case UserMediaController::GetUserMediaAccess::InsecureParent:
+ domWindow.printErrorMessage(makeString("Trying to call ", callerName, " from a document with an insecure parent frame."));
+ break;
+ case UserMediaController::GetUserMediaAccess::BlockedByParent:
+ domWindow.printErrorMessage(makeString("The top-level frame has prevented a document with a different security origin from calling ", callerName, "."));
+ break;
+ case UserMediaController::GetUserMediaAccess::CanCall:
+ break;
+ }
+}
+
} // namespace WebCore
#endif // ENABLE(MEDIA_STREAM)
Modified: trunk/Source/WebCore/Modules/mediastream/UserMediaController.h (237769 => 237770)
--- trunk/Source/WebCore/Modules/mediastream/UserMediaController.h 2018-11-03 06:25:56 UTC (rev 237769)
+++ trunk/Source/WebCore/Modules/mediastream/UserMediaController.h 2018-11-03 13:30:30 UTC (rev 237770)
@@ -51,6 +51,20 @@
UserMediaClient::DeviceChangeObserverToken addDeviceChangeObserver(WTF::Function<void()>&&);
void removeDeviceChangeObserver(UserMediaClient::DeviceChangeObserverToken);
+ enum class GetUserMediaAccess {
+ CanCall,
+ InsecureDocument,
+ InsecureParent,
+ BlockedByParent
+ };
+ GetUserMediaAccess canCallGetUserMedia(Document&, bool wantsAudio, bool wantsVideo);
+
+ enum class BlockedCaller {
+ GetUserMedia,
+ EnumerateDevices
+ };
+ void logGetUserMediaDenial(Document&, GetUserMediaAccess, BlockedCaller);
+
WEBCORE_EXPORT static const char* supplementName();
static UserMediaController* from(Page* page) { return static_cast<UserMediaController*>(Supplement<Page>::from(page, supplementName())); }
Modified: trunk/Source/WebCore/Modules/mediastream/UserMediaRequest.cpp (237769 => 237770)
--- trunk/Source/WebCore/Modules/mediastream/UserMediaRequest.cpp 2018-11-03 06:25:56 UTC (rev 237769)
+++ trunk/Source/WebCore/Modules/mediastream/UserMediaRequest.cpp 2018-11-03 13:30:30 UTC (rev 237770)
@@ -1,7 +1,7 @@
/*
* Copyright (C) 2011 Ericsson AB. All rights reserved.
* Copyright (C) 2012 Google Inc. All rights reserved.
- * Copyright (C) 2013-2017 Apple Inc. All rights reserved.
+ * Copyright (C) 2013-2018 Apple Inc. All rights reserved.
* Copyright (C) 2013 Nokia Corporation and/or its subsidiary(-ies).
*
* Redistribution and use in source and binary forms, with or without
@@ -36,13 +36,8 @@
#if ENABLE(MEDIA_STREAM)
-#include "CaptureDeviceManager.h"
-#include "DeprecatedGlobalSettings.h"
#include "Document.h"
-#include "DocumentLoader.h"
#include "Frame.h"
-#include "HTMLIFrameElement.h"
-#include "HTMLParserIdioms.h"
#include "JSMediaStream.h"
#include "JSOverconstrainedError.h"
#include "Logging.h"
@@ -84,78 +79,6 @@
return &m_scriptExecutionContext->topOrigin();
}
-static bool isSecure(DocumentLoader& documentLoader)
-{
- auto& response = documentLoader.response();
- if (SecurityOrigin::isLocalHostOrLoopbackIPAddress(documentLoader.response().url().host()))
- return true;
- return SchemeRegistry::shouldTreatURLSchemeAsSecure(response.url().protocol().toStringWithoutCopying())
- && response.certificateInfo()
- && !response.certificateInfo()->containsNonRootSHA1SignedCertificate();
-}
-
-static bool isAllowedToUse(Document& document, Document& topDocument, bool requiresAudio, bool requiresVideo)
-{
- if (&document == &topDocument)
- return true;
-
- auto* parentDocument = document.parentDocument();
- if (!parentDocument)
- return false;
-
- if (document.securityOrigin().isSameSchemeHostPort(parentDocument->securityOrigin()))
- return true;
-
- auto* element = document.ownerElement();
- ASSERT(element);
- if (!element)
- return false;
-
- if (!is<HTMLIFrameElement>(*element))
- return false;
- auto& allow = downcast<HTMLIFrameElement>(*element).allow();
-
- bool allowCameraAccess = false;
- bool allowMicrophoneAccess = false;
- for (auto allowItem : StringView { allow }.split(';')) {
- auto item = allowItem.stripLeadingAndTrailingMatchedCharacters(isHTMLSpace<UChar>);
- if (!allowCameraAccess && item == "camera")
- allowCameraAccess = true;
- else if (!allowMicrophoneAccess && item == "microphone")
- allowMicrophoneAccess = true;
- }
- return (allowCameraAccess || !requiresVideo) && (allowMicrophoneAccess || !requiresAudio);
-}
-
-static bool canCallGetUserMedia(Document& document, bool wantsAudio, bool wantsVideo, String& errorMessage)
-{
- ASSERT(wantsAudio || wantsVideo);
-
- bool requiresSecureConnection = DeprecatedGlobalSettings::mediaCaptureRequiresSecureConnection();
- auto& documentLoader = *document.loader();
- if (requiresSecureConnection && !isSecure(documentLoader)) {
- errorMessage = "Trying to call getUserMedia from an insecure document.";
- return false;
- }
-
- auto& topDocument = document.topDocument();
- if (&document != &topDocument) {
- for (auto* ancestorDocument = &document; ancestorDocument != &topDocument; ancestorDocument = ancestorDocument->parentDocument()) {
- if (requiresSecureConnection && !isSecure(*ancestorDocument->loader())) {
- errorMessage = "Trying to call getUserMedia from a document with an insecure parent frame.";
- return false;
- }
-
- if (!isAllowedToUse(*ancestorDocument, topDocument, wantsAudio, wantsVideo)) {
- errorMessage = "The top-level frame has prevented a document with a different security origin to call getUserMedia.";
- return false;
- }
- }
- }
-
- return true;
-}
-
static bool hasInvalidGetDisplayMediaConstraint(const MediaConstraints& constraints)
{
// https://w3c.github.io/mediacapture-screen-share/#navigator-additions
@@ -266,10 +189,10 @@
// ...
// 6.10 Permission Failure: Reject p with a new DOMException object whose name attribute has
// the value NotAllowedError.
- String errorMessage;
- if (!canCallGetUserMedia(document, m_request.audioConstraints.isValid, m_request.videoConstraints.isValid, errorMessage)) {
+ auto access = controller->canCallGetUserMedia(document, m_request.audioConstraints.isValid, m_request.videoConstraints.isValid);
+ if (access != UserMediaController::GetUserMediaAccess::CanCall) {
deny(MediaAccessDenialReason::PermissionDenied);
- document.domWindow()->printErrorMessage(errorMessage);
+ controller->logGetUserMediaDenial(document, access, UserMediaController::BlockedCaller::GetUserMedia);
return;
}