Title: [216160] trunk
Revision
216160
Author
eric.carl...@apple.com
Date
2017-05-03 17:03:29 -0700 (Wed, 03 May 2017)

Log Message

[MediaStream] Allow host application to enable/disable media capture
https://bugs.webkit.org/show_bug.cgi?id=171292
<rdar://problem/31821492>

Reviewed by Jer Noble.

Source/WebCore:

No new layout tests, added an API test instead.

* Modules/mediastream/MediaStream.cpp:
(WebCore::MediaStream::endStream): New, stop all tracks.
* Modules/mediastream/MediaStream.h:

* Modules/mediastream/MediaStreamRegistry.cpp:
(WebCore::MediaStreamRegistry::unregisterStream): Minor cleanup.
(WebCore::MediaStreamRegistry::forEach): New, call the lambda with each stream.
(WebCore::MediaStreamRegistry::MediaStreamRegistry): Deleted, unused.
* Modules/mediastream/MediaStreamRegistry.h:

* Modules/mediastream/MediaStreamTrack.cpp:
(WebCore::MediaStreamTrack::stopTrack): Add parameter so caller can specify if an 'ended' 
event should be sent or not.
(WebCore::MediaStreamTrack::trackMutedChanged): Don't post an event if the track has ended.
* Modules/mediastream/MediaStreamTrack.h:

* dom/Document.cpp:
(WebCore::Document::stopMediaCapture): Stop all streams in the document.
* dom/Document.h:

* page/Page.cpp:
(WebCore::Page::stopMediaCapture): Stop all streams.
* page/Page.h:

* platform/graphics/avfoundation/objc/MediaPlayerPrivateMediaStreamAVFObjC.mm:
(WebCore::MediaPlayerPrivateMediaStreamAVFObjC::currentDisplayMode): Display a black frame
when the stream ends.
(WebCore::MediaPlayerPrivateMediaStreamAVFObjC::activeStatusChanged): Signal a characteristics
change to HTMLMediaElement refresh state.
* platform/mediastream/MediaStreamPrivate.h:

* platform/mediastream/mac/AVMediaCaptureSource.mm:
(WebCore::AVMediaCaptureSource::stopProducingData): Don't return early if the session isn't 
running, we always need to clear m_session on iOS.

Source/WebKit2:

* UIProcess/API/C/WKPage.cpp:
(WKPageSetMediaCaptureEnabled): New.
(WKPageGetMediaCaptureEnabled): New.
(WKPageClearUserMediaState): Deleted, unused.
* UIProcess/API/C/WKPagePrivate.h:

* UIProcess/API/Cocoa/WKWebView.mm:
(-[WKWebView _setMediaCaptureEnabled:]): New.
(-[WKWebView _mediaCaptureEnabled]): New.
* UIProcess/API/Cocoa/WKWebViewPrivate.h:

* UIProcess/Cocoa/UIDelegate.mm:
(WebKit::UIDelegate::setDelegate): Initialize webViewRequestUserMediaAuthorizationForDevicesURLMainFrameURLDecisionHandler
and webViewCheckUserMediaPermissionForURLMainFrameURLFrameIdentifierDecisionHandler on macOS
and iOS.

* UIProcess/UserMediaPermissionRequestManagerProxy.cpp:
(WebKit::UserMediaPermissionRequestManagerProxy::UserMediaPermissionRequestManagerProxy):
Initialize the rejection timer.
(WebKit::UserMediaPermissionRequestManagerProxy::~UserMediaPermissionRequestManagerProxy):
Call invalidatePendingRequests.
(WebKit::UserMediaPermissionRequestManagerProxy::invalidatePendingRequests): Invalidate all
pending requests.
(WebKit::UserMediaPermissionRequestManagerProxy::stopCapture): New.
(WebKit::UserMediaPermissionRequestManagerProxy::rejectionTimerFired): Reject a promise and
schedule the timer if there are any others pending.
(WebKit::UserMediaPermissionRequestManagerProxy::scheduleNextRejection): 
(WebKit::UserMediaPermissionRequestManagerProxy::requestUserMediaPermissionForFrame): Don't
prompt the user if capture is disabled.
(WebKit::UserMediaPermissionRequestManagerProxy::invalidateRequests): Deleted.
(WebKit::UserMediaPermissionRequestManagerProxy::clearCachedState): Deleted.
* UIProcess/UserMediaPermissionRequestManagerProxy.h:

* UIProcess/UserMediaProcessManager.cpp:
(WebKit::UserMediaProcessManager::willEnableMediaStreamInPage): Stop capture in the current
page on iOS.
(WebKit::UserMediaProcessManager::setCaptureEnabled):
* UIProcess/UserMediaProcessManager.h:

* UIProcess/WebPageProxy.cpp:
(WebKit::WebPageProxy::setMediaCaptureEnabled):
(WebKit::WebPageProxy::clearUserMediaState): Deleted.

* UIProcess/WebPageProxy.h:
(WebKit::WebPageProxy::mediaCaptureEnabled):

* WebProcess/MediaStream/UserMediaPermissionRequestManager.cpp:
(WebKit::UserMediaPermissionRequestManager::cancelPendingRequests): New, cancel all pending
requests.
(WebKit::UserMediaPermissionRequestManager::cancelUserMediaRequest): Deny the request.
(WebKit::UserMediaPermissionRequestManager::cancelMediaDevicesEnumeration):
* WebProcess/MediaStream/UserMediaPermissionRequestManager.h:

* WebProcess/WebPage/WebPage.cpp:
(WebKit::WebPage::stopMediaCapture):
* WebProcess/WebPage/WebPage.h:
* WebProcess/WebPage/WebPage.messages.in:

Tools:

* TestWebKitAPI/TestWebKitAPI.xcodeproj/project.pbxproj:
* TestWebKitAPI/Tests/WebKit2Cocoa/UserMediaDisabled.mm: Added.
(-[UserMediaMessageHandler userContentController:didReceiveScriptMessage:]):
(-[UserMediaUIDelegate _webView:requestUserMediaAuthorizationForDevices:url:mainFrameURL:decisionHandler:]):
(-[UserMediaUIDelegate _webView:checkUserMediaPermissionForURL:mainFrameURL:frameIdentifier:decisionHandler:]):
(MediaCaptureDisabledTest::SetUp):
(MediaCaptureDisabledTest::loadTestAndWaitForMessage):
(TEST_F):
* TestWebKitAPI/Tests/WebKit2Cocoa/disableGetUserMedia.html: Added.

Modified Paths

Added Paths

Diff

Modified: trunk/Source/WebCore/ChangeLog (216159 => 216160)


--- trunk/Source/WebCore/ChangeLog	2017-05-03 23:57:18 UTC (rev 216159)
+++ trunk/Source/WebCore/ChangeLog	2017-05-04 00:03:29 UTC (rev 216160)
@@ -1,3 +1,48 @@
+2017-05-03  Eric Carlson  <eric.carl...@apple.com>
+
+        [MediaStream] Allow host application to enable/disable media capture
+        https://bugs.webkit.org/show_bug.cgi?id=171292
+        <rdar://problem/31821492>
+
+        Reviewed by Jer Noble.
+
+        No new layout tests, added an API test instead.
+
+        * Modules/mediastream/MediaStream.cpp:
+        (WebCore::MediaStream::endStream): New, stop all tracks.
+        * Modules/mediastream/MediaStream.h:
+
+        * Modules/mediastream/MediaStreamRegistry.cpp:
+        (WebCore::MediaStreamRegistry::unregisterStream): Minor cleanup.
+        (WebCore::MediaStreamRegistry::forEach): New, call the lambda with each stream.
+        (WebCore::MediaStreamRegistry::MediaStreamRegistry): Deleted, unused.
+        * Modules/mediastream/MediaStreamRegistry.h:
+
+        * Modules/mediastream/MediaStreamTrack.cpp:
+        (WebCore::MediaStreamTrack::stopTrack): Add parameter so caller can specify if an 'ended' 
+        event should be sent or not.
+        (WebCore::MediaStreamTrack::trackMutedChanged): Don't post an event if the track has ended.
+        * Modules/mediastream/MediaStreamTrack.h:
+
+        * dom/Document.cpp:
+        (WebCore::Document::stopMediaCapture): Stop all streams in the document.
+        * dom/Document.h:
+
+        * page/Page.cpp:
+        (WebCore::Page::stopMediaCapture): Stop all streams.
+        * page/Page.h:
+
+        * platform/graphics/avfoundation/objc/MediaPlayerPrivateMediaStreamAVFObjC.mm:
+        (WebCore::MediaPlayerPrivateMediaStreamAVFObjC::currentDisplayMode): Display a black frame
+        when the stream ends.
+        (WebCore::MediaPlayerPrivateMediaStreamAVFObjC::activeStatusChanged): Signal a characteristics
+        change to HTMLMediaElement refresh state.
+        * platform/mediastream/MediaStreamPrivate.h:
+
+        * platform/mediastream/mac/AVMediaCaptureSource.mm:
+        (WebCore::AVMediaCaptureSource::stopProducingData): Don't return early if the session isn't 
+        running, we always need to clear m_session on iOS.
+
 2017-05-03  Zalan Bujtas  <za...@apple.com>
 
         SearchInputType could end up with a mismatched renderer.

Modified: trunk/Source/WebCore/Modules/mediastream/MediaStream.cpp (216159 => 216160)


--- trunk/Source/WebCore/Modules/mediastream/MediaStream.cpp	2017-05-03 23:57:18 UTC (rev 216159)
+++ trunk/Source/WebCore/Modules/mediastream/MediaStream.cpp	2017-05-04 00:03:29 UTC (rev 216160)
@@ -314,6 +314,12 @@
     m_private->stopProducingData();
 }
 
+void MediaStream::endStream()
+{
+    for (auto& track : m_trackSet.values())
+        track->stopTrack(MediaStreamTrack::StopMode::PostEvent);
+}
+
 void MediaStream::pageMutedStateDidChange()
 {
     if (!m_isActive)

Modified: trunk/Source/WebCore/Modules/mediastream/MediaStream.h (216159 => 216160)


--- trunk/Source/WebCore/Modules/mediastream/MediaStream.h	2017-05-03 23:57:18 UTC (rev 216159)
+++ trunk/Source/WebCore/Modules/mediastream/MediaStream.h	2017-05-04 00:03:29 UTC (rev 216160)
@@ -91,6 +91,8 @@
     void startProducingData();
     void stopProducingData();
 
+    void endStream();
+
     // EventTarget
     EventTargetInterface eventTargetInterface() const final { return MediaStreamEventTargetInterfaceType; }
     ScriptExecutionContext* scriptExecutionContext() const final { return ContextDestructionObserver::scriptExecutionContext(); }
@@ -106,6 +108,8 @@
 
     void addTrackFromPlatform(Ref<MediaStreamTrack>&&);
 
+    Document* document() const;
+
 protected:
     MediaStream(ScriptExecutionContext&, const MediaStreamTrackVector&);
     MediaStream(ScriptExecutionContext&, Ref<MediaStreamPrivate>&&);
@@ -158,8 +162,6 @@
     void setIsActive(bool);
     void statusDidChange();
 
-    Document* document() const;
-
     MediaStreamTrackVector trackVectorForType(RealtimeMediaSource::Type) const;
 
     Ref<MediaStreamPrivate> m_private;

Modified: trunk/Source/WebCore/Modules/mediastream/MediaStreamRegistry.cpp (216159 => 216160)


--- trunk/Source/WebCore/Modules/mediastream/MediaStreamRegistry.cpp	2017-05-03 23:57:18 UTC (rev 216159)
+++ trunk/Source/WebCore/Modules/mediastream/MediaStreamRegistry.cpp	2017-05-04 00:03:29 UTC (rev 216160)
@@ -62,10 +62,6 @@
     return m_mediaStreams.get(url);
 }
 
-MediaStreamRegistry::MediaStreamRegistry()
-{
-}
-
 MediaStream* MediaStreamRegistry::lookUp(const URL& url) const
 {
     return static_cast<MediaStream*>(lookup(url.string()));
@@ -84,21 +80,16 @@
 
 void MediaStreamRegistry::unregisterStream(MediaStream& stream)
 {
-    Vector<MediaStream*>& allStreams = mediaStreams();
+    auto& allStreams = mediaStreams();
     size_t pos = allStreams.find(&stream);
     if (pos != notFound)
         allStreams.remove(pos);
 }
 
-MediaStream* MediaStreamRegistry::lookUp(const MediaStreamPrivate& privateStream) const
+void MediaStreamRegistry::forEach(std::function<void(MediaStream&)> callback) const
 {
-    Vector<MediaStream*>& allStreams = mediaStreams();
-    for (auto& stream : allStreams) {
-        if (&stream->privateStream() == &privateStream)
-            return stream;
-    }
-
-    return nullptr;
+    for (auto& stream : mediaStreams())
+        callback(*stream);
 }
 
 } // namespace WebCore

Modified: trunk/Source/WebCore/Modules/mediastream/MediaStreamRegistry.h (216159 => 216160)


--- trunk/Source/WebCore/Modules/mediastream/MediaStreamRegistry.h	2017-05-03 23:57:18 UTC (rev 216159)
+++ trunk/Source/WebCore/Modules/mediastream/MediaStreamRegistry.h	2017-05-04 00:03:29 UTC (rev 216160)
@@ -54,10 +54,11 @@
     void unregisterStream(MediaStream&);
 
     MediaStream* lookUp(const URL&) const;
-    MediaStream* lookUp(const MediaStreamPrivate&) const;
 
+    void forEach(std::function<void(MediaStream&)>) const;
+
 private:
-    MediaStreamRegistry();
+    MediaStreamRegistry() = default;
     HashMap<String, RefPtr<MediaStream>> m_mediaStreams;
 };
 

Modified: trunk/Source/WebCore/Modules/mediastream/MediaStreamTrack.cpp (216159 => 216160)


--- trunk/Source/WebCore/Modules/mediastream/MediaStreamTrack.cpp	2017-05-03 23:57:18 UTC (rev 216159)
+++ trunk/Source/WebCore/Modules/mediastream/MediaStreamTrack.cpp	2017-05-04 00:03:29 UTC (rev 216160)
@@ -113,7 +113,7 @@
     return MediaStreamTrack::create(*scriptExecutionContext(), m_private->clone());
 }
 
-void MediaStreamTrack::stopTrack()
+void MediaStreamTrack::stopTrack(StopMode mode)
 {
     // NOTE: this method is called when the "stop" method is called from JS, using the "ImplementedAs" IDL attribute.
     // This is done because ActiveDOMObject requires a "stop" method.
@@ -121,8 +121,13 @@
     if (ended())
         return;
 
+    // An 'ended' event is not posted if m_ended is true when trackEnded is called, so set it now if we are
+    // not supposed to post the event.
+    if (mode == StopMode::Silently)
+        m_ended = true;
+
+    m_private->endTrack();
     m_ended = true;
-    m_private->endTrack();
 }
 
 MediaStreamTrack::TrackSettings MediaStreamTrack::getSettings() const
@@ -303,7 +308,7 @@
     
 void MediaStreamTrack::trackMutedChanged(MediaStreamTrackPrivate&)
 {
-    if (scriptExecutionContext()->activeDOMObjectsAreSuspended() || scriptExecutionContext()->activeDOMObjectsAreStopped())
+    if (scriptExecutionContext()->activeDOMObjectsAreSuspended() || scriptExecutionContext()->activeDOMObjectsAreStopped() || m_ended)
         return;
 
     AtomicString eventType = muted() ? eventNames().muteEvent : eventNames().unmuteEvent;

Modified: trunk/Source/WebCore/Modules/mediastream/MediaStreamTrack.h (216159 => 216160)


--- trunk/Source/WebCore/Modules/mediastream/MediaStreamTrack.h	2017-05-03 23:57:18 UTC (rev 216159)
+++ trunk/Source/WebCore/Modules/mediastream/MediaStreamTrack.h	2017-05-04 00:03:29 UTC (rev 216160)
@@ -71,8 +71,10 @@
     bool ended() const;
 
     Ref<MediaStreamTrack> clone();
-    void stopTrack();
 
+    enum class StopMode { Silently, PostEvent };
+    void stopTrack(StopMode = StopMode::Silently);
+
     bool isCaptureTrack() const;
 
     struct TrackSettings {

Modified: trunk/Source/WebCore/dom/Document.cpp (216159 => 216160)


--- trunk/Source/WebCore/dom/Document.cpp	2017-05-03 23:57:18 UTC (rev 216159)
+++ trunk/Source/WebCore/dom/Document.cpp	2017-05-04 00:03:29 UTC (rev 216160)
@@ -271,6 +271,11 @@
 #include "XSLTProcessor.h"
 #endif
 
+#if ENABLE(MEDIA_STREAM)
+#include "MediaStream.h"
+#include "MediaStreamRegistry.h"
+#endif
+
 using namespace WTF;
 using namespace Unicode;
 
@@ -6972,4 +6977,14 @@
     m_orientationNotifier.orientationChanged(orientation);
 }
 
+#if ENABLE(MEDIA_STREAM)
+void Document::stopMediaCapture()
+{
+    MediaStreamRegistry::shared().forEach([this](MediaStream& stream) {
+        if (stream.document() == this)
+            stream.endStream();
+    });
+}
+#endif
+
 } // namespace WebCore

Modified: trunk/Source/WebCore/dom/Document.h (216159 => 216160)


--- trunk/Source/WebCore/dom/Document.h	2017-05-03 23:57:18 UTC (rev 216159)
+++ trunk/Source/WebCore/dom/Document.h	2017-05-04 00:03:29 UTC (rev 216160)
@@ -1277,6 +1277,7 @@
     bool hasHadActiveMediaStreamTrack() const { return m_hasHadActiveMediaStreamTrack; }
     void setDeviceIDHashSalt(const String& salt) { m_idHashSalt = salt; }
     String deviceIDHashSalt() const { return m_idHashSalt; }
+    void stopMediaCapture();
 #endif
 
 // FIXME: Find a better place for this functionality.

Modified: trunk/Source/WebCore/page/Page.cpp (216159 => 216160)


--- trunk/Source/WebCore/page/Page.cpp	2017-05-03 23:57:18 UTC (rev 216159)
+++ trunk/Source/WebCore/page/Page.cpp	2017-05-04 00:03:29 UTC (rev 216160)
@@ -1532,6 +1532,18 @@
     }
 }
 
+void Page::stopMediaCapture()
+{
+#if ENABLE(MEDIA_STREAM)
+    for (Frame* frame = &mainFrame(); frame; frame = frame->tree().traverseNext()) {
+        if (!frame->document())
+            continue;
+
+        frame->document()->stopMediaCapture();
+    }
+#endif
+}
+
 #if ENABLE(MEDIA_SESSION)
 void Page::handleMediaEvent(MediaEventType eventType)
 {

Modified: trunk/Source/WebCore/page/Page.h (216159 => 216160)


--- trunk/Source/WebCore/page/Page.h	2017-05-03 23:57:18 UTC (rev 216159)
+++ trunk/Source/WebCore/page/Page.h	2017-05-04 00:03:29 UTC (rev 216160)
@@ -530,6 +530,7 @@
     bool isAudioMuted() const { return m_mutedState & MediaProducer::AudioIsMuted; }
     bool isMediaCaptureMuted() const { return m_mutedState & MediaProducer::CaptureDevicesAreMuted; };
     WEBCORE_EXPORT void setMuted(MediaProducer::MutedStateFlags);
+    WEBCORE_EXPORT void stopMediaCapture();
 
 #if ENABLE(MEDIA_SESSION)
     WEBCORE_EXPORT void handleMediaEvent(MediaEventType);

Modified: trunk/Source/WebCore/platform/graphics/avfoundation/objc/MediaPlayerPrivateMediaStreamAVFObjC.mm (216159 => 216160)


--- trunk/Source/WebCore/platform/graphics/avfoundation/objc/MediaPlayerPrivateMediaStreamAVFObjC.mm	2017-05-03 23:57:18 UTC (rev 216159)
+++ trunk/Source/WebCore/platform/graphics/avfoundation/objc/MediaPlayerPrivateMediaStreamAVFObjC.mm	2017-05-04 00:03:29 UTC (rev 216160)
@@ -580,21 +580,21 @@
 
 MediaPlayerPrivateMediaStreamAVFObjC::DisplayMode MediaPlayerPrivateMediaStreamAVFObjC::currentDisplayMode() const
 {
-    if (m_ended || m_intrinsicSize.isEmpty() || !metaDataAvailable() || !m_sampleBufferDisplayLayer)
+    if (m_intrinsicSize.isEmpty() || !metaDataAvailable() || !m_sampleBufferDisplayLayer)
         return None;
 
     if (auto* track = m_mediaStreamPrivate->activeVideoTrack()) {
-        if (!track->enabled() || track->muted())
+        if (!track->enabled() || track->muted() || track->ended())
             return PaintItBlack;
     }
 
-    if (playing()) {
+    if (playing() && !m_ended) {
         if (!m_mediaStreamPrivate->isProducingData())
             return PausedImage;
         return LivePreview;
     }
 
-    if (m_playbackState == PlaybackState::None)
+    if (m_playbackState == PlaybackState::None || m_ended)
         return PaintItBlack;
 
     return PausedImage;
@@ -768,8 +768,10 @@
 
         if (ended != m_ended) {
             m_ended = ended;
-            if (m_player)
+            if (m_player) {
                 m_player->timeChanged();
+                m_player->characteristicChanged();
+            }
         }
     });
 }

Modified: trunk/Source/WebCore/platform/mediastream/MediaStreamPrivate.h (216159 => 216160)


--- trunk/Source/WebCore/platform/mediastream/MediaStreamPrivate.h	2017-05-03 23:57:18 UTC (rev 216159)
+++ trunk/Source/WebCore/platform/mediastream/MediaStreamPrivate.h	2017-05-04 00:03:29 UTC (rev 216160)
@@ -95,6 +95,8 @@
     void stopProducingData();
     bool isProducingData() const;
 
+    void endStream();
+
     bool hasVideo() const;
     bool hasAudio() const;
     bool muted() const;

Modified: trunk/Source/WebCore/platform/mediastream/mac/AVMediaCaptureSource.mm (216159 => 216160)


--- trunk/Source/WebCore/platform/mediastream/mac/AVMediaCaptureSource.mm	2017-05-03 23:57:18 UTC (rev 216159)
+++ trunk/Source/WebCore/platform/mediastream/mac/AVMediaCaptureSource.mm	2017-05-04 00:03:29 UTC (rev 216160)
@@ -181,11 +181,14 @@
 
 void AVMediaCaptureSource::stopProducingData()
 {
-    if (!m_session || ![m_session isRunning])
+    if (!m_session)
         return;
 
     [m_objcObserver removeNotificationObservers];
-    [m_session stopRunning];
+
+    if ([m_session isRunning])
+        [m_session stopRunning];
+
 #if PLATFORM(IOS)
     m_session = nullptr;
 #endif

Modified: trunk/Source/WebKit2/ChangeLog (216159 => 216160)


--- trunk/Source/WebKit2/ChangeLog	2017-05-03 23:57:18 UTC (rev 216159)
+++ trunk/Source/WebKit2/ChangeLog	2017-05-04 00:03:29 UTC (rev 216160)
@@ -1,3 +1,69 @@
+2017-05-03  Eric Carlson  <eric.carl...@apple.com>
+
+        [MediaStream] Allow host application to enable/disable media capture
+        https://bugs.webkit.org/show_bug.cgi?id=171292
+        <rdar://problem/31821492>
+
+        Reviewed by Jer Noble.
+
+        * UIProcess/API/C/WKPage.cpp:
+        (WKPageSetMediaCaptureEnabled): New.
+        (WKPageGetMediaCaptureEnabled): New.
+        (WKPageClearUserMediaState): Deleted, unused.
+        * UIProcess/API/C/WKPagePrivate.h:
+
+        * UIProcess/API/Cocoa/WKWebView.mm:
+        (-[WKWebView _setMediaCaptureEnabled:]): New.
+        (-[WKWebView _mediaCaptureEnabled]): New.
+        * UIProcess/API/Cocoa/WKWebViewPrivate.h:
+
+        * UIProcess/Cocoa/UIDelegate.mm:
+        (WebKit::UIDelegate::setDelegate): Initialize webViewRequestUserMediaAuthorizationForDevicesURLMainFrameURLDecisionHandler
+        and webViewCheckUserMediaPermissionForURLMainFrameURLFrameIdentifierDecisionHandler on macOS
+        and iOS.
+
+        * UIProcess/UserMediaPermissionRequestManagerProxy.cpp:
+        (WebKit::UserMediaPermissionRequestManagerProxy::UserMediaPermissionRequestManagerProxy):
+        Initialize the rejection timer.
+        (WebKit::UserMediaPermissionRequestManagerProxy::~UserMediaPermissionRequestManagerProxy):
+        Call invalidatePendingRequests.
+        (WebKit::UserMediaPermissionRequestManagerProxy::invalidatePendingRequests): Invalidate all
+        pending requests.
+        (WebKit::UserMediaPermissionRequestManagerProxy::stopCapture): New.
+        (WebKit::UserMediaPermissionRequestManagerProxy::rejectionTimerFired): Reject a promise and
+        schedule the timer if there are any others pending.
+        (WebKit::UserMediaPermissionRequestManagerProxy::scheduleNextRejection): 
+        (WebKit::UserMediaPermissionRequestManagerProxy::requestUserMediaPermissionForFrame): Don't
+        prompt the user if capture is disabled.
+        (WebKit::UserMediaPermissionRequestManagerProxy::invalidateRequests): Deleted.
+        (WebKit::UserMediaPermissionRequestManagerProxy::clearCachedState): Deleted.
+        * UIProcess/UserMediaPermissionRequestManagerProxy.h:
+
+        * UIProcess/UserMediaProcessManager.cpp:
+        (WebKit::UserMediaProcessManager::willEnableMediaStreamInPage): Stop capture in the current
+        page on iOS.
+        (WebKit::UserMediaProcessManager::setCaptureEnabled):
+        * UIProcess/UserMediaProcessManager.h:
+
+        * UIProcess/WebPageProxy.cpp:
+        (WebKit::WebPageProxy::setMediaCaptureEnabled):
+        (WebKit::WebPageProxy::clearUserMediaState): Deleted.
+
+        * UIProcess/WebPageProxy.h:
+        (WebKit::WebPageProxy::mediaCaptureEnabled):
+
+        * WebProcess/MediaStream/UserMediaPermissionRequestManager.cpp:
+        (WebKit::UserMediaPermissionRequestManager::cancelPendingRequests): New, cancel all pending
+        requests.
+        (WebKit::UserMediaPermissionRequestManager::cancelUserMediaRequest): Deny the request.
+        (WebKit::UserMediaPermissionRequestManager::cancelMediaDevicesEnumeration):
+        * WebProcess/MediaStream/UserMediaPermissionRequestManager.h:
+
+        * WebProcess/WebPage/WebPage.cpp:
+        (WebKit::WebPage::stopMediaCapture):
+        * WebProcess/WebPage/WebPage.h:
+        * WebProcess/WebPage/WebPage.messages.in:
+
 2017-05-03  Tim Horton  <timothy_hor...@apple.com>
 
         Maintain interaction information URL as a URL, not a string

Modified: trunk/Source/WebKit2/UIProcess/API/C/WKPage.cpp (216159 => 216160)


--- trunk/Source/WebKit2/UIProcess/API/C/WKPage.cpp	2017-05-03 23:57:18 UTC (rev 216159)
+++ trunk/Source/WebKit2/UIProcess/API/C/WKPage.cpp	2017-05-04 00:03:29 UTC (rev 216160)
@@ -2677,6 +2677,16 @@
     toImpl(page)->setMuted(muted);
 }
 
+void WKPageSetMediaCaptureEnabled(WKPageRef page, bool enabled)
+{
+    toImpl(page)->setMediaCaptureEnabled(enabled);
+}
+
+bool WKPageGetMediaCaptureEnabled(WKPageRef page)
+{
+    return toImpl(page)->mediaCaptureEnabled();
+}
+
 void WKPageDidAllowPointerLock(WKPageRef page)
 {
 #if ENABLE(POINTER_LOCK)

Modified: trunk/Source/WebKit2/UIProcess/API/C/WKPagePrivate.h (216159 => 216160)


--- trunk/Source/WebKit2/UIProcess/API/C/WKPagePrivate.h	2017-05-03 23:57:18 UTC (rev 216159)
+++ trunk/Source/WebKit2/UIProcess/API/C/WKPagePrivate.h	2017-05-04 00:03:29 UTC (rev 216160)
@@ -127,6 +127,8 @@
 WK_EXPORT void WKPageSetMuted(WKPageRef page, WKMediaMutedState muted);
 
 WK_EXPORT void WKPageClearUserMediaState(WKPageRef page);
+WK_EXPORT void WKPageSetMediaCaptureEnabled(WKPageRef page, bool enabled);
+WK_EXPORT bool WKPageGetMediaCaptureEnabled(WKPageRef page);
 
 WK_EXPORT void WKPageDidAllowPointerLock(WKPageRef page);
 WK_EXPORT void WKPageDidDenyPointerLock(WKPageRef page);

Modified: trunk/Source/WebKit2/UIProcess/API/Cocoa/WKWebView.mm (216159 => 216160)


--- trunk/Source/WebKit2/UIProcess/API/Cocoa/WKWebView.mm	2017-05-03 23:57:18 UTC (rev 216159)
+++ trunk/Source/WebKit2/UIProcess/API/Cocoa/WKWebView.mm	2017-05-04 00:03:29 UTC (rev 216160)
@@ -4473,6 +4473,16 @@
     _page->setMuted(WebCore::MediaProducer::CaptureDevicesAreMuted);
 }
 
+- (void)_setMediaCaptureEnabled:(BOOL)enabled
+{
+    _page->setMediaCaptureEnabled(enabled);
+}
+
+- (BOOL)_mediaCaptureEnabled
+{
+    return _page->mediaCaptureEnabled();
+}
+
 - (void)_setPageMuted:(_WKMediaMutedState)mutedState
 {
     WebCore::MediaProducer::MutedStateFlags coreState = WebCore::MediaProducer::NoneMuted;

Modified: trunk/Source/WebKit2/UIProcess/API/Cocoa/WKWebViewPrivate.h (216159 => 216160)


--- trunk/Source/WebKit2/UIProcess/API/Cocoa/WKWebViewPrivate.h	2017-05-03 23:57:18 UTC (rev 216159)
+++ trunk/Source/WebKit2/UIProcess/API/Cocoa/WKWebViewPrivate.h	2017-05-04 00:03:29 UTC (rev 216160)
@@ -292,9 +292,11 @@
 @property (nonatomic, setter=_setFullscreenDelegate:) id<_WKFullscreenDelegate> _fullscreenDelegate WK_API_AVAILABLE(macosx(WK_MAC_TBA));
 @property (nonatomic, readonly) BOOL _isInFullscreen WK_API_AVAILABLE(macosx(WK_MAC_TBA));
 
-- (void)_muteMediaCapture;
+- (void)_muteMediaCapture WK_API_AVAILABLE(macosx(WK_MAC_TBA), ios(WK_IOS_TBA));
 - (void)_setPageMuted:(_WKMediaMutedState)mutedState WK_API_AVAILABLE(macosx(WK_MAC_TBA), ios(WK_IOS_TBA));
 
+@property (nonatomic, setter=_setMediaCaptureEnabled:) BOOL _mediaCaptureEnabled WK_API_AVAILABLE(macosx(WK_MAC_TBA), ios(WK_IOS_TBA));
+
 @end
 
 #if !TARGET_OS_IPHONE

Modified: trunk/Source/WebKit2/UIProcess/Cocoa/UIDelegate.mm (216159 => 216160)


--- trunk/Source/WebKit2/UIProcess/Cocoa/UIDelegate.mm	2017-05-03 23:57:18 UTC (rev 216159)
+++ trunk/Source/WebKit2/UIProcess/Cocoa/UIDelegate.mm	2017-05-04 00:03:29 UTC (rev 216160)
@@ -115,11 +115,11 @@
 #endif
     m_delegateMethods.webViewActionsForElementDefaultActions = [delegate respondsToSelector:@selector(_webView:actionsForElement:defaultActions:)];
     m_delegateMethods.webViewDidNotHandleTapAsClickAtPoint = [delegate respondsToSelector:@selector(_webView:didNotHandleTapAsClickAtPoint:)];
+    m_delegateMethods.presentingViewControllerForWebView = [delegate respondsToSelector:@selector(_presentingViewControllerForWebView:)];
+#endif
     m_delegateMethods.webViewRequestUserMediaAuthorizationForDevicesURLMainFrameURLDecisionHandler = [delegate respondsToSelector:@selector(_webView:requestUserMediaAuthorizationForDevices:url:mainFrameURL:decisionHandler:)];
     m_delegateMethods.webViewCheckUserMediaPermissionForURLMainFrameURLFrameIdentifierDecisionHandler = [delegate respondsToSelector:@selector(_webView:checkUserMediaPermissionForURL:mainFrameURL:frameIdentifier:decisionHandler:)];
     m_delegateMethods.webViewMediaCaptureStateDidChange = [delegate respondsToSelector:@selector(_webView:mediaCaptureStateDidChange:)];
-    m_delegateMethods.presentingViewControllerForWebView = [delegate respondsToSelector:@selector(_presentingViewControllerForWebView:)];
-#endif
     m_delegateMethods.dataDetectionContextForWebView = [delegate respondsToSelector:@selector(_dataDetectionContextForWebView:)];
     m_delegateMethods.webViewImageOrMediaDocumentSizeChanged = [delegate respondsToSelector:@selector(_webView:imageOrMediaDocumentSizeChanged:)];
 

Modified: trunk/Source/WebKit2/UIProcess/UserMediaPermissionRequestManagerProxy.cpp (216159 => 216160)


--- trunk/Source/WebKit2/UIProcess/UserMediaPermissionRequestManagerProxy.cpp	2017-05-03 23:57:18 UTC (rev 216159)
+++ trunk/Source/WebKit2/UIProcess/UserMediaPermissionRequestManagerProxy.cpp	2017-05-04 00:03:29 UTC (rev 216160)
@@ -96,6 +96,7 @@
 
 UserMediaPermissionRequestManagerProxy::UserMediaPermissionRequestManagerProxy(WebPageProxy& page)
     : m_page(page)
+    , m_rejectionTimer(*this, &UserMediaPermissionRequestManagerProxy::rejectionTimerFired)
 {
 #if ENABLE(MEDIA_STREAM)
     UserMediaProcessManager::singleton().addUserMediaPermissionRequestManagerProxy(*this);
@@ -107,10 +108,10 @@
 #if ENABLE(MEDIA_STREAM)
     UserMediaProcessManager::singleton().removeUserMediaPermissionRequestManagerProxy(*this);
 #endif
-    invalidateRequests();
+    invalidatePendingRequests();
 }
 
-void UserMediaPermissionRequestManagerProxy::invalidateRequests()
+void UserMediaPermissionRequestManagerProxy::invalidatePendingRequests()
 {
     for (auto& request : m_pendingUserMediaRequests.values())
         request->invalidate();
@@ -123,9 +124,10 @@
     m_frameStates.clear();
 }
 
-void UserMediaPermissionRequestManagerProxy::clearCachedState()
+void UserMediaPermissionRequestManagerProxy::stopCapture()
 {
-    invalidateRequests();
+    invalidatePendingRequests();
+    m_page.process().send(Messages::WebPage::StopMediaCapture(), m_page.pageID());
 }
 
 Ref<UserMediaPermissionRequestProxy> UserMediaPermissionRequestManagerProxy::createRequest(uint64_t userMediaID, uint64_t frameID, const String& userMediaDocumentOriginIdentifier, const String& topLevelDocumentOriginIdentifier, const Vector<String>& audioDeviceUIDs, const Vector<String>& videoDeviceUIDs)
@@ -223,6 +225,23 @@
 #endif
 }
 
+void UserMediaPermissionRequestManagerProxy::rejectionTimerFired()
+{
+    uint64_t userMediaID = m_pendingRejections[0];
+    m_pendingRejections.remove(0);
+
+    denyRequest(userMediaID, UserMediaPermissionRequestProxy::UserMediaAccessDenialReason::PermissionDenied, emptyString());
+    if (!m_pendingRejections.isEmpty())
+        scheduleNextRejection();
+}
+
+void UserMediaPermissionRequestManagerProxy::scheduleNextRejection()
+{
+    const double mimimumDelayBeforeReplying = .25;
+    if (!m_rejectionTimer.isActive())
+        m_rejectionTimer.startOneShot(Seconds(mimimumDelayBeforeReplying + randomNumber()));
+}
+
 void UserMediaPermissionRequestManagerProxy::requestUserMediaPermissionForFrame(uint64_t userMediaID, uint64_t frameID, String userMediaDocumentOriginIdentifier, String topLevelDocumentOriginIdentifier, const WebCore::MediaConstraintsData& audioConstraintsData, const WebCore::MediaConstraintsData& videoConstraintsData)
 {
 #if ENABLE(MEDIA_STREAM)
@@ -272,6 +291,12 @@
 
     };
 
+    if (!UserMediaProcessManager::singleton().captureEnabled()) {
+        m_pendingRejections.append(userMediaID);
+        scheduleNextRejection();
+        return;
+    }
+
     auto audioConstraints = MediaConstraintsImpl::create(MediaConstraintsData(audioConstraintsData));
     auto videoConstraints = MediaConstraintsImpl::create(MediaConstraintsData(videoConstraintsData));
 

Modified: trunk/Source/WebKit2/UIProcess/UserMediaPermissionRequestManagerProxy.h (216159 => 216160)


--- trunk/Source/WebKit2/UIProcess/UserMediaPermissionRequestManagerProxy.h	2017-05-03 23:57:18 UTC (rev 216159)
+++ trunk/Source/WebKit2/UIProcess/UserMediaPermissionRequestManagerProxy.h	2017-05-04 00:03:29 UTC (rev 216160)
@@ -17,14 +17,15 @@
  *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
  */
 
-#ifndef UserMediaPermissionRequestManagerProxy_h
-#define UserMediaPermissionRequestManagerProxy_h
+#pragma once
 
 #include "UserMediaPermissionCheckProxy.h"
 #include "UserMediaPermissionRequestProxy.h"
 #include <WebCore/SecurityOrigin.h>
+#include <WebCore/Timer.h>
 #include <WebCore/UserMediaRequest.h>
 #include <wtf/HashMap.h>
+#include <wtf/Seconds.h>
 
 namespace WebCore {
 class CaptureDevice;
@@ -57,7 +58,7 @@
 
     WebPageProxy& page() const { return m_page; }
 
-    void invalidateRequests();
+    void invalidatePendingRequests();
 
     void requestUserMediaPermissionForFrame(uint64_t userMediaID, uint64_t frameID, String userMediaDocumentOriginIdentifier, String topLevelDocumentOriginIdentifier, const WebCore::MediaConstraintsData& audioConstraintsData, const WebCore::MediaConstraintsData& videoConstraintsData);
 
@@ -69,7 +70,9 @@
 
     void didCompleteUserMediaPermissionCheck(uint64_t, const String&, bool allow);
 
-    void clearCachedState();
+    void stopCapture();
+    void scheduleNextRejection();
+    void rejectionTimerFired();
 
     void startedCaptureSession();
     void endedCaptureSession();
@@ -85,8 +88,10 @@
     HashMap<uint64_t, std::unique_ptr<FrameAuthorizationState>> m_frameStates;
 
     WebPageProxy& m_page;
+
+    WebCore::Timer m_rejectionTimer;
+    Vector<uint64_t> m_pendingRejections;
 };
 
 } // namespace WebKit
 
-#endif // UserMediaPermissionRequestManagerProxy_h

Modified: trunk/Source/WebKit2/UIProcess/UserMediaProcessManager.cpp (216159 => 216160)


--- trunk/Source/WebKit2/UIProcess/UserMediaProcessManager.cpp	2017-05-03 23:57:18 UTC (rev 216159)
+++ trunk/Source/WebKit2/UIProcess/UserMediaProcessManager.cpp	2017-05-04 00:03:29 UTC (rev 216160)
@@ -115,8 +115,12 @@
     for (auto& state : stateMap()) {
         for (auto& manager : state.value->managers()) {
 
-            if (&manager->page() == &pageStartingCapture)
+            if (&manager->page() == &pageStartingCapture) {
+#if PLATFORM(IOS)
+                manager->page().stopCapture();
+#endif
                 continue;
+            }
 
             manager->page().setMuted(WebCore::MediaProducer::CaptureDevicesAreMuted);
         }
@@ -230,6 +234,22 @@
 #endif
 }
 
+void UserMediaProcessManager::setCaptureEnabled(bool enabled)
+{
+    if (enabled == m_captureEnabled)
+        return;
+
+    m_captureEnabled = enabled;
+
+    if (enabled)
+        return;
+
+    for (auto& state : stateMap()) {
+        for (auto& manager : state.value->managers())
+            manager->stopCapture();
+    }
+}
+
 } // namespace WebKit
 
 #endif

Modified: trunk/Source/WebKit2/UIProcess/UserMediaProcessManager.h (216159 => 216160)


--- trunk/Source/WebKit2/UIProcess/UserMediaProcessManager.h	2017-05-03 23:57:18 UTC (rev 216159)
+++ trunk/Source/WebKit2/UIProcess/UserMediaProcessManager.h	2017-05-04 00:03:29 UTC (rev 216160)
@@ -39,6 +39,12 @@
 
     void startedCaptureSession(UserMediaPermissionRequestManagerProxy&);
     void endedCaptureSession(UserMediaPermissionRequestManagerProxy&);
+
+    void setCaptureEnabled(bool);
+    bool captureEnabled() const { return m_captureEnabled; }
+
+private:
+    bool m_captureEnabled { true };
 };
 
 } // namespace WebKit

Modified: trunk/Source/WebKit2/UIProcess/WebPageProxy.cpp (216159 => 216160)


--- trunk/Source/WebKit2/UIProcess/WebPageProxy.cpp	2017-05-03 23:57:18 UTC (rev 216159)
+++ trunk/Source/WebKit2/UIProcess/WebPageProxy.cpp	2017-05-04 00:03:29 UTC (rev 216160)
@@ -4206,6 +4206,18 @@
     activityStateDidChange(ActivityState::IsAudible | ActivityState::IsCapturingMedia);
 }
 
+void WebPageProxy::setMediaCaptureEnabled(bool enabled)
+{
+    m_mediaCaptureEnabled = enabled;
+
+    if (!isValid())
+        return;
+
+#if ENABLE(MEDIA_STREAM)
+    UserMediaProcessManager::singleton().setCaptureEnabled(enabled);
+#endif
+}
+
 #if ENABLE(MEDIA_SESSION)
 void WebPageProxy::handleMediaEvent(MediaEventType eventType)
 {
@@ -5771,13 +5783,6 @@
 #endif
 }
 
-void WebPageProxy::clearUserMediaState()
-{
-#if ENABLE(MEDIA_STREAM)
-    userMediaPermissionRequestManager().clearCachedState();
-#endif
-}
-
 void WebPageProxy::requestNotificationPermission(uint64_t requestID, const String& originString)
 {
     if (!isRequestIDValid(requestID))

Modified: trunk/Source/WebKit2/UIProcess/WebPageProxy.h (216159 => 216160)


--- trunk/Source/WebKit2/UIProcess/WebPageProxy.h	2017-05-03 23:57:18 UTC (rev 216159)
+++ trunk/Source/WebKit2/UIProcess/WebPageProxy.h	2017-05-04 00:03:29 UTC (rev 216160)
@@ -979,6 +979,9 @@
     void setMuted(WebCore::MediaProducer::MutedStateFlags);
     void setMayStartMediaWhenInWindow(bool);
     bool mayStartMediaWhenInWindow() const { return m_mayStartMediaWhenInWindow; }
+    void setMediaCaptureEnabled(bool);
+    bool mediaCaptureEnabled() const { return m_mediaCaptureEnabled; }
+
         
 #if ENABLE(MEDIA_SESSION)
     bool hasMediaSessionWithActiveMediaElements() const { return m_hasMediaSessionWithActiveMediaElements; }
@@ -1192,8 +1195,6 @@
 
     void isLoadingChanged() { activityStateDidChange(WebCore::ActivityState::IsLoading); }
 
-    void clearUserMediaState();
-
     void setShouldSkipWaitingForPaintAfterNextViewDidMoveToWindow(bool shouldSkip) { m_shouldSkipWaitingForPaintAfterNextViewDidMoveToWindow = shouldSkip; }
 
     void setURLSchemeHandlerForScheme(Ref<WebURLSchemeHandler>&&, const String& scheme);
@@ -1935,6 +1936,7 @@
     float m_mediaVolume;
     WebCore::MediaProducer::MutedStateFlags m_mutedState { WebCore::MediaProducer::NoneMuted };
     bool m_mayStartMediaWhenInWindow;
+    bool m_mediaCaptureEnabled { true };
 
     bool m_waitingForDidUpdateActivityState;
 

Modified: trunk/Source/WebKit2/WebProcess/MediaStream/UserMediaPermissionRequestManager.cpp (216159 => 216160)


--- trunk/Source/WebKit2/WebProcess/MediaStream/UserMediaPermissionRequestManager.cpp	2017-05-03 23:57:18 UTC (rev 216159)
+++ trunk/Source/WebKit2/WebProcess/MediaStream/UserMediaPermissionRequestManager.cpp	2017-05-04 00:03:29 UTC (rev 216160)
@@ -56,6 +56,15 @@
         sandboxExtension.value->revoke();
 }
 
+void UserMediaPermissionRequestManager::cancelPendingRequests()
+{
+    for (auto& request : m_idToUserMediaRequestMap.values())
+        cancelUserMediaRequest(*request);
+
+    for (auto& request : m_idToMediaDevicesEnumerationRequestMap.values())
+        cancelMediaDevicesEnumeration(*request);
+}
+
 void UserMediaPermissionRequestManager::startUserMediaRequest(UserMediaRequest& request)
 {
     Document* document = request.document();
@@ -104,6 +113,8 @@
     uint64_t requestID = m_userMediaRequestToIDMap.take(&request);
     if (!requestID)
         return;
+
+    request.deny(UserMediaRequest::OtherFailure, emptyString());
     m_idToUserMediaRequestMap.remove(requestID);
     removeMediaRequestFromMaps(request);
 }
@@ -190,6 +201,7 @@
     uint64_t requestID = m_mediaDevicesEnumerationRequestToIDMap.take(&request);
     if (!requestID)
         return;
+    request.setDeviceInfo(Vector<CaptureDevice>(), emptyString(), false);
     m_idToMediaDevicesEnumerationRequestMap.remove(requestID);
 }
 

Modified: trunk/Source/WebKit2/WebProcess/MediaStream/UserMediaPermissionRequestManager.h (216159 => 216160)


--- trunk/Source/WebKit2/WebProcess/MediaStream/UserMediaPermissionRequestManager.h	2017-05-03 23:57:18 UTC (rev 216159)
+++ trunk/Source/WebKit2/WebProcess/MediaStream/UserMediaPermissionRequestManager.h	2017-05-04 00:03:29 UTC (rev 216160)
@@ -55,6 +55,8 @@
     void grantUserMediaDeviceSandboxExtensions(const MediaDeviceSandboxExtensions&);
     void revokeUserMediaDeviceSandboxExtensions(const Vector<String>&);
 
+    void cancelPendingRequests();
+
 private:
     void sendUserMediaRequest(WebCore::UserMediaRequest&);
 

Modified: trunk/Source/WebKit2/WebProcess/WebPage/WebPage.cpp (216159 => 216160)


--- trunk/Source/WebKit2/WebProcess/WebPage/WebPage.cpp	2017-05-03 23:57:18 UTC (rev 216159)
+++ trunk/Source/WebKit2/WebProcess/WebPage/WebPage.cpp	2017-05-04 00:03:29 UTC (rev 216160)
@@ -4556,6 +4556,14 @@
     m_page->setMuted(state);
 }
 
+void WebPage::stopMediaCapture()
+{
+#if ENABLE(MEDIA_STREAM)
+    m_userMediaPermissionRequestManager.cancelPendingRequests();
+    m_page->stopMediaCapture();
+#endif
+}
+
 #if ENABLE(MEDIA_SESSION)
 void WebPage::handleMediaEvent(uint32_t eventType)
 {

Modified: trunk/Source/WebKit2/WebProcess/WebPage/WebPage.h (216159 => 216160)


--- trunk/Source/WebKit2/WebProcess/WebPage/WebPage.h	2017-05-03 23:57:18 UTC (rev 216159)
+++ trunk/Source/WebKit2/WebProcess/WebPage/WebPage.h	2017-05-04 00:03:29 UTC (rev 216160)
@@ -765,6 +765,7 @@
     void setMediaVolume(float);
     void setMuted(WebCore::MediaProducer::MutedStateFlags);
     void setMayStartMediaWhenInWindow(bool);
+    void stopMediaCapture();
 
 #if ENABLE(MEDIA_SESSION)
     void handleMediaEvent(uint32_t /* WebCore::MediaEventType */);

Modified: trunk/Source/WebKit2/WebProcess/WebPage/WebPage.messages.in (216159 => 216160)


--- trunk/Source/WebKit2/WebProcess/WebPage/WebPage.messages.in	2017-05-03 23:57:18 UTC (rev 216159)
+++ trunk/Source/WebKit2/WebProcess/WebPage/WebPage.messages.in	2017-05-04 00:03:29 UTC (rev 216160)
@@ -338,6 +338,7 @@
     SetMediaVolume(float volume)
     SetMuted(WebCore::MediaProducer::MutedStateFlags muted)
     SetMayStartMediaWhenInWindow(bool mayStartMedia)
+    StopMediaCapture()
 
 #if ENABLE(MEDIA_SESSION)
     HandleMediaEvent(uint32_t eventType)

Modified: trunk/Tools/ChangeLog (216159 => 216160)


--- trunk/Tools/ChangeLog	2017-05-03 23:57:18 UTC (rev 216159)
+++ trunk/Tools/ChangeLog	2017-05-04 00:03:29 UTC (rev 216160)
@@ -1,3 +1,21 @@
+2017-05-03  Eric Carlson  <eric.carl...@apple.com>
+
+        [MediaStream] Allow host application to enable/disable media capture
+        https://bugs.webkit.org/show_bug.cgi?id=171292
+        <rdar://problem/31821492>
+
+        Reviewed by Jer Noble.
+
+        * TestWebKitAPI/TestWebKitAPI.xcodeproj/project.pbxproj:
+        * TestWebKitAPI/Tests/WebKit2Cocoa/UserMediaDisabled.mm: Added.
+        (-[UserMediaMessageHandler userContentController:didReceiveScriptMessage:]):
+        (-[UserMediaUIDelegate _webView:requestUserMediaAuthorizationForDevices:url:mainFrameURL:decisionHandler:]):
+        (-[UserMediaUIDelegate _webView:checkUserMediaPermissionForURL:mainFrameURL:frameIdentifier:decisionHandler:]):
+        (MediaCaptureDisabledTest::SetUp):
+        (MediaCaptureDisabledTest::loadTestAndWaitForMessage):
+        (TEST_F):
+        * TestWebKitAPI/Tests/WebKit2Cocoa/disableGetUserMedia.html: Added.
+
 2017-04-26  Jiewen Tan  <jiewen_...@apple.com>
 
         [WebCrypto] Add an api test for testing wrapping/unwrapping serialized crypto keys

Modified: trunk/Tools/TestWebKitAPI/TestWebKitAPI.xcodeproj/project.pbxproj (216159 => 216160)


--- trunk/Tools/TestWebKitAPI/TestWebKitAPI.xcodeproj/project.pbxproj	2017-05-03 23:57:18 UTC (rev 216159)
+++ trunk/Tools/TestWebKitAPI/TestWebKitAPI.xcodeproj/project.pbxproj	2017-05-04 00:03:29 UTC (rev 216160)
@@ -25,6 +25,8 @@
 		07492B3B1DF8B14C00633DE1 /* EnumerateMediaDevices.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 07492B3A1DF8AE2D00633DE1 /* EnumerateMediaDevices.cpp */; };
 		07492B3C1DF8B86600633DE1 /* enumerateMediaDevices.html in Copy Resources */ = {isa = PBXBuildFile; fileRef = 07492B391DF8ADA400633DE1 /* enumerateMediaDevices.html */; };
 		074994421EA5034B000DA44E /* getUserMedia.html in Copy Resources */ = {isa = PBXBuildFile; fileRef = 4A410F4D19AF7BEF002EBAB5 /* getUserMedia.html */; };
+		0799C3491EBA2D7B003B7532 /* UserMediaDisabled.mm in Sources */ = {isa = PBXBuildFile; fileRef = 07EDEFAC1EB9400C00D43292 /* UserMediaDisabled.mm */; };
+		0799C34B1EBA3301003B7532 /* disableGetUserMedia.html in Copy Resources */ = {isa = PBXBuildFile; fileRef = 0799C34A1EBA32F4003B7532 /* disableGetUserMedia.html */; };
 		07C046CA1E4262A8007201E7 /* CARingBuffer.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 07C046C91E42573E007201E7 /* CARingBuffer.cpp */; };
 		0F139E771A423A5B00F590F5 /* WeakObjCPtr.mm in Sources */ = {isa = PBXBuildFile; fileRef = 0F139E751A423A5300F590F5 /* WeakObjCPtr.mm */; };
 		0F139E781A423A6B00F590F5 /* PlatformUtilitiesCocoa.mm in Sources */ = {isa = PBXBuildFile; fileRef = 0F139E721A423A2B00F590F5 /* PlatformUtilitiesCocoa.mm */; };
@@ -687,6 +689,7 @@
 			files = (
 				55226A2F1EBA44B900C36AD0 /* large-red-square-image.html in Copy Resources */,
 				5797FE331EB15AB100B2F4A0 /* navigation-client-default-crypto.html in Copy Resources */,
+				0799C34B1EBA3301003B7532 /* disableGetUserMedia.html in Copy Resources */,
 				074994421EA5034B000DA44E /* getUserMedia.html in Copy Resources */,
 				C9BF06EF1E9C132500595E3E /* autoplay-muted-with-controls.html in Copy Resources */,
 				F4DEF6ED1E9B4DB60048EF61 /* image-in-link-and-input.html in Copy Resources */,
@@ -879,7 +882,9 @@
 		07492B391DF8ADA400633DE1 /* enumerateMediaDevices.html */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.html; path = enumerateMediaDevices.html; sourceTree = "<group>"; };
 		07492B3A1DF8AE2D00633DE1 /* EnumerateMediaDevices.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = EnumerateMediaDevices.cpp; sourceTree = "<group>"; };
 		0766DD1F1A5AD5200023E3BB /* PendingAPIRequestURL.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = PendingAPIRequestURL.cpp; sourceTree = "<group>"; };
+		0799C34A1EBA32F4003B7532 /* disableGetUserMedia.html */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.html; path = disableGetUserMedia.html; sourceTree = "<group>"; };
 		07C046C91E42573E007201E7 /* CARingBuffer.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = CARingBuffer.cpp; sourceTree = "<group>"; };
+		07EDEFAC1EB9400C00D43292 /* UserMediaDisabled.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = UserMediaDisabled.mm; sourceTree = "<group>"; };
 		0BCD833414857CE400EA2003 /* HashMap.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = HashMap.cpp; sourceTree = "<group>"; };
 		0BCD85691485C98B00EA2003 /* SetForScope.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = SetForScope.cpp; sourceTree = "<group>"; };
 		0F139E721A423A2B00F590F5 /* PlatformUtilitiesCocoa.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; name = PlatformUtilitiesCocoa.mm; path = cocoa/PlatformUtilitiesCocoa.mm; sourceTree = "<group>"; };
@@ -1671,6 +1676,7 @@
 			children = (
 				A16F66B81C40E9E100BD4D24 /* Resources */,
 				7CEFA9641AC0B9E200B910FD /* _WKUserContentExtensionStore.mm */,
+				07EDEFAC1EB9400C00D43292 /* UserMediaDisabled.mm */,
 				37E7DD631EA06FF2009B396D /* AdditionalReadAccessAllowedURLs.mm */,
 				37E7DD661EA071F3009B396D /* AdditionalReadAccessAllowedURLsPlugin.mm */,
 				37E7DD651EA0715B009B396D /* AdditionalReadAccessAllowedURLsProtocol.h */,
@@ -1896,6 +1902,7 @@
 				2EFF06C61D886A560004BB30 /* change-video-source-on-end.html */,
 				A16F66B91C40EA2000BD4D24 /* ContentFiltering.html */,
 				5C2936941D5BFD1900DEAB1E /* CookieMessage.html */,
+				0799C34A1EBA32F4003B7532 /* disableGetUserMedia.html */,
 				837A35F01D9A1E6400663C57 /* DownloadRequestBlobURL.html */,
 				5714ECB81CA8B58800051AC8 /* DownloadRequestOriginalURL.html */,
 				5714ECBC1CA8C21800051AC8 /* DownloadRequestOriginalURL2.html */,
@@ -3079,6 +3086,7 @@
 				D34E08761E4E42E1005FF14A /* WKWebViewGetContents.mm in Sources */,
 				315231CA1EB3B3C700A22A16 /* GPUCommandQueue.mm in Sources */,
 				F4FA91811E61849B007B8C1D /* WKWebViewSelectionTests.mm in Sources */,
+				0799C3491EBA2D7B003B7532 /* UserMediaDisabled.mm in Sources */,
 				93F56DA91E5F919D003EDE84 /* WKWebViewSnapshot.mm in Sources */,
 				9984FACC1CFFAF60008D198C /* WKWebViewTextInput.mm in Sources */,
 				764322D71B61CCC30024F801 /* WordBoundaryTypingAttributes.mm in Sources */,

Added: trunk/Tools/TestWebKitAPI/Tests/WebKit2Cocoa/UserMediaDisabled.mm (0 => 216160)


--- trunk/Tools/TestWebKitAPI/Tests/WebKit2Cocoa/UserMediaDisabled.mm	                        (rev 0)
+++ trunk/Tools/TestWebKitAPI/Tests/WebKit2Cocoa/UserMediaDisabled.mm	2017-05-04 00:03:29 UTC (rev 216160)
@@ -0,0 +1,143 @@
+/*
+ * Copyright (C) 2016 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#import "config.h"
+
+#import "PlatformUtilities.h"
+#import "Test.h"
+#import "TestWKWebView.h"
+
+#import <WebKit/WKPreferencesPrivate.h>
+#import <WebKit/WKUserContentControllerPrivate.h>
+#import <WebKit/WKWebViewConfigurationPrivate.h>
+#import <WebKit/WKWebViewPrivate.h>
+#import <WebKit/WebKit.h>
+#import <WebKit/_WKProcessPoolConfiguration.h>
+#import <wtf/RetainPtr.h>
+
+#if WK_API_ENABLED
+
+static bool refuseRequest = false;
+static bool wasPrompted = false;
+
+static bool receivedScriptMessage = false;
+static RetainPtr<WKScriptMessage> lastScriptMessage;
+
+@interface UserMediaMessageHandler : NSObject <WKScriptMessageHandler>
+@end
+
+@implementation UserMediaMessageHandler
+
+- (void)userContentController:(WKUserContentController *)userContentController didReceiveScriptMessage:(WKScriptMessage *)message
+{
+    lastScriptMessage = message;
+    receivedScriptMessage = true;
+}
+@end
+
+@interface UserMediaUIDelegate : NSObject <WKUIDelegate>
+@end
+
+@implementation UserMediaUIDelegate
+
+- (void)_webView:(WKWebView *)webView requestUserMediaAuthorizationForDevices:(NSUInteger)devices url:(NSURL *)url mainFrameURL:(NSURL *)mainFrameURL decisionHandler:(void (^)(BOOL))decisionHandler
+{
+    wasPrompted = true;
+
+    if (refuseRequest) {
+        decisionHandler(NO);
+        return;
+    }
+
+    BOOL needsMicrophoneAuthorized = devices & _WKCaptureDeviceMicrophone;
+    BOOL needsCameraAuthorized = devices & _WKCaptureDeviceCamera;
+    if (!needsMicrophoneAuthorized && !needsCameraAuthorized) {
+        decisionHandler(NO);
+        return;
+    }
+
+    decisionHandler(YES);
+}
+
+- (void)_webView:(WKWebView *)webView checkUserMediaPermissionForURL:(NSURL *)url mainFrameURL:(NSURL *)mainFrameURL frameIdentifier:(NSUInteger)frameIdentifier decisionHandler:(void (^)(NSString *, BOOL))decisionHandler
+{
+    if (refuseRequest) {
+        decisionHandler(nil, NO);
+        return;
+    }
+}
+@end
+
+class MediaCaptureDisabledTest : public testing::Test {
+public:
+    virtual void SetUp()
+    {
+        m_configuration = adoptNS([[WKWebViewConfiguration alloc] init]);
+
+        RetainPtr<UserMediaMessageHandler> handler = adoptNS([[UserMediaMessageHandler alloc] init]);
+        [[m_configuration userContentController] addScriptMessageHandler:handler.get() name:@"testHandler"];
+
+        m_webView = adoptNS([[TestWKWebView alloc] initWithFrame:NSMakeRect(0, 0, 800, 600) configuration:m_configuration.get()]);
+
+        auto preferences = [m_webView configuration].preferences;
+        preferences._mediaDevicesEnabled = YES;
+        preferences._mockCaptureDevicesEnabled = YES;
+        preferences._mediaCaptureRequiresSecureConnection = NO;
+
+        m_uiDelegate = adoptNS([[UserMediaUIDelegate alloc] init]);
+        [m_webView setUIDelegate:m_uiDelegate.get()];
+    }
+
+    void loadTestAndWaitForMessage(const char* message)
+    {
+        wasPrompted = false;
+        receivedScriptMessage = false;
+        [m_webView loadTestPageNamed:@"disableGetUserMedia"];
+        TestWebKitAPI::Util::run(&receivedScriptMessage);
+        EXPECT_STREQ([(NSString *)[lastScriptMessage body] UTF8String], message);
+    }
+
+    RetainPtr<WKWebViewConfiguration> m_configuration;
+    RetainPtr<UserMediaUIDelegate> m_uiDelegate;
+    RetainPtr<TestWKWebView> m_webView;
+};
+
+TEST_F(MediaCaptureDisabledTest, EnableAndDisable)
+{
+    EXPECT_TRUE(m_webView.get()._mediaCaptureEnabled);
+    loadTestAndWaitForMessage("allowed");
+    EXPECT_TRUE(wasPrompted);
+
+    m_webView.get()._mediaCaptureEnabled = NO;
+    EXPECT_FALSE(m_webView.get()._mediaCaptureEnabled);
+    loadTestAndWaitForMessage("denied");
+    EXPECT_FALSE(wasPrompted);
+
+    m_webView.get()._mediaCaptureEnabled = YES;
+    EXPECT_TRUE(m_webView.get()._mediaCaptureEnabled);
+    loadTestAndWaitForMessage("allowed");
+    EXPECT_TRUE(wasPrompted);
+}
+#endif

Added: trunk/Tools/TestWebKitAPI/Tests/WebKit2Cocoa/disableGetUserMedia.html (0 => 216160)


--- trunk/Tools/TestWebKitAPI/Tests/WebKit2Cocoa/disableGetUserMedia.html	                        (rev 0)
+++ trunk/Tools/TestWebKitAPI/Tests/WebKit2Cocoa/disableGetUserMedia.html	2017-05-04 00:03:29 UTC (rev 216160)
@@ -0,0 +1,16 @@
+<script>
+    function gotUserMedia(mediaStream)
+    {
+        window.webkit.messageHandlers.testHandler.postMessage('gUM allowed');
+    }
+
+    function userMediaError(error)
+    {
+        window.webkit.messageHandlers.testHandler.postMessage('gUM denied');
+    }
+
+    var constraints = { audio: false, video: true};
+    navigator.mediaDevices.getUserMedia(constraints)
+        .then(gotUserMedia).
+        catch(userMediaError);
+</script>
_______________________________________________
webkit-changes mailing list
webkit-changes@lists.webkit.org
https://lists.webkit.org/mailman/listinfo/webkit-changes

Reply via email to