<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN"
"http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head><meta http-equiv="content-type" content="text/html; charset=utf-8" />
<title>[209010] trunk/Source/WebKit2</title>
</head>
<body>

<style type="text/css"><!--
#msg dl.meta { border: 1px #006 solid; background: #369; padding: 6px; color: #fff; }
#msg dl.meta dt { float: left; width: 6em; font-weight: bold; }
#msg dt:after { content:':';}
#msg dl, #msg dt, #msg ul, #msg li, #header, #footer, #logmsg { font-family: verdana,arial,helvetica,sans-serif; font-size: 10pt;  }
#msg dl a { font-weight: bold}
#msg dl a:link    { color:#fc3; }
#msg dl a:active  { color:#ff0; }
#msg dl a:visited { color:#cc6; }
h3 { font-family: verdana,arial,helvetica,sans-serif; font-size: 10pt; font-weight: bold; }
#msg pre { overflow: auto; background: #ffc; border: 1px #fa0 solid; padding: 6px; }
#logmsg { background: #ffc; border: 1px #fa0 solid; padding: 1em 1em 0 1em; }
#logmsg p, #logmsg pre, #logmsg blockquote { margin: 0 0 1em 0; }
#logmsg p, #logmsg li, #logmsg dt, #logmsg dd { line-height: 14pt; }
#logmsg h1, #logmsg h2, #logmsg h3, #logmsg h4, #logmsg h5, #logmsg h6 { margin: .5em 0; }
#logmsg h1:first-child, #logmsg h2:first-child, #logmsg h3:first-child, #logmsg h4:first-child, #logmsg h5:first-child, #logmsg h6:first-child { margin-top: 0; }
#logmsg ul, #logmsg ol { padding: 0; list-style-position: inside; margin: 0 0 0 1em; }
#logmsg ul { text-indent: -1em; padding-left: 1em; }#logmsg ol { text-indent: -1.5em; padding-left: 1.5em; }
#logmsg > ul, #logmsg > ol { margin: 0 0 1em 0; }
#logmsg pre { background: #eee; padding: 1em; }
#logmsg blockquote { border: 1px solid #fa0; border-left-width: 10px; padding: 1em 1em 0 1em; background: white;}
#logmsg dl { margin: 0; }
#logmsg dt { font-weight: bold; }
#logmsg dd { margin: 0; padding: 0 0 0.5em 0; }
#logmsg dd:before { content:'\00bb';}
#logmsg table { border-spacing: 0px; border-collapse: collapse; border-top: 4px solid #fa0; border-bottom: 1px solid #fa0; background: #fff; }
#logmsg table th { text-align: left; font-weight: normal; padding: 0.2em 0.5em; border-top: 1px dotted #fa0; }
#logmsg table td { text-align: right; border-top: 1px dotted #fa0; padding: 0.2em 0.5em; }
#logmsg table thead th { text-align: center; border-bottom: 1px solid #fa0; }
#logmsg table th.Corner { text-align: left; }
#logmsg hr { border: none 0; border-top: 2px dashed #fa0; height: 1px; }
#header, #footer { color: #fff; background: #636; border: 1px #300 solid; padding: 6px; }
#patch { width: 100%; }
#patch h4 {font-family: verdana,arial,helvetica,sans-serif;font-size:10pt;padding:8px;background:#369;color:#fff;margin:0;}
#patch .propset h4, #patch .binary h4 {margin:0;}
#patch pre {padding:0;line-height:1.2em;margin:0;}
#patch .diff {width:100%;background:#eee;padding: 0 0 10px 0;overflow:auto;}
#patch .propset .diff, #patch .binary .diff  {padding:10px 0;}
#patch span {display:block;padding:0 10px;}
#patch .modfile, #patch .addfile, #patch .delfile, #patch .propset, #patch .binary, #patch .copfile {border:1px solid #ccc;margin:10px 0;}
#patch ins {background:#dfd;text-decoration:none;display:block;padding:0 10px;}
#patch del {background:#fdd;text-decoration:none;display:block;padding:0 10px;}
#patch .lines, .info {color:#888;background:#fff;}
--></style>
<div id="msg">
<dl class="meta">
<dt>Revision</dt> <dd><a href="http://trac.webkit.org/projects/webkit/changeset/209010">209010</a></dd>
<dt>Author</dt> <dd>commit-queue@webkit.org</dd>
<dt>Date</dt> <dd>2016-11-28 12:46:44 -0800 (Mon, 28 Nov 2016)</dd>
</dl>

<h3>Log Message</h3>
<pre>Support for HTML Media Capture API
https://bugs.webkit.org/show_bug.cgi?id=43239

Patch by Andrew Gold &lt;agold@apple.com&gt; on 2016-11-28
Reviewed by Tim Horton.

In order to enable media capture on iOS, we must first use the AVFoundation API to
check/request capture permission from the user for Safari. Then, Safari must request
permission on behalf of the webpage to use the capture devices. Additionally, Safari
must present UI when the capture is taking place, so WebKit needs to notify the client
of a capture session beginning and ending. To do this, we added four methods to
WKUIDelegatePrivate to request permission from the user, check for permissions, notify
that a capture session has begun, and notify that a capture session has ended. Additionally,
we added a private method to WKWebView that allows the client to stop a capture session.

* UIProcess/API/APIUIClient.h:
(API::UIClient::didBeginCaptureSession): Notifies the client of a capture session beginning.
(API::UIClient::didEndCaptureSession): Notifies the client of a capture session ending.

* UIProcess/API/Cocoa/WKUIDelegatePrivate.h: Added new delegate methods to request permission,
check for permission, notify of a capture session beginning, and notify of a capture session
ending.

* UIProcess/API/Cocoa/WKWebView.mm:
(-[WKWebView _stopMediaCapture]): Cancels a media capture session.
* UIProcess/API/Cocoa/WKWebViewPrivate.h:

* UIProcess/Cocoa/UIDelegate.h:
* UIProcess/Cocoa/UIDelegate.mm:
(WebKit::UIDelegate::setDelegate): Added the new delegate methods.
(WebKit::UIDelegate::UIClient::decidePolicyForUserMediaPermissionRequest):
First checks if the user has authorized the client application access capture devices,
then uses the WKUIDelegate to request permission for a site from the user.
(WebKit::UIDelegate::UIClient::checkUserMediaPermissionForOrigin): Checks the client
for permission to access capture devices.
(WebKit::UIDelegate::UIClient::didBeginCaptureSession): Notifies the client of a capture
session beginning.
(WebKit::UIDelegate::UIClient::didEndCaptureSession): Notifies the client of a capture
session ending.

* UIProcess/WebPageProxy.cpp:
(WebKit::WebPageProxy::isPlayingMediaDidChange): Calls UIDelegate method to notify the
client of a capture session beginning/ending.</pre>

<h3>Modified Paths</h3>
<ul>
<li><a href="#trunkSourceWebKit2ChangeLog">trunk/Source/WebKit2/ChangeLog</a></li>
<li><a href="#trunkSourceWebKit2UIProcessAPIAPIUIClienth">trunk/Source/WebKit2/UIProcess/API/APIUIClient.h</a></li>
<li><a href="#trunkSourceWebKit2UIProcessAPICocoaWKUIDelegatePrivateh">trunk/Source/WebKit2/UIProcess/API/Cocoa/WKUIDelegatePrivate.h</a></li>
<li><a href="#trunkSourceWebKit2UIProcessAPICocoaWKWebViewmm">trunk/Source/WebKit2/UIProcess/API/Cocoa/WKWebView.mm</a></li>
<li><a href="#trunkSourceWebKit2UIProcessAPICocoaWKWebViewPrivateh">trunk/Source/WebKit2/UIProcess/API/Cocoa/WKWebViewPrivate.h</a></li>
<li><a href="#trunkSourceWebKit2UIProcessCocoaUIDelegateh">trunk/Source/WebKit2/UIProcess/Cocoa/UIDelegate.h</a></li>
<li><a href="#trunkSourceWebKit2UIProcessCocoaUIDelegatemm">trunk/Source/WebKit2/UIProcess/Cocoa/UIDelegate.mm</a></li>
<li><a href="#trunkSourceWebKit2UIProcessWebPageProxycpp">trunk/Source/WebKit2/UIProcess/WebPageProxy.cpp</a></li>
</ul>

</div>
<div id="patch">
<h3>Diff</h3>
<a id="trunkSourceWebKit2ChangeLog"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebKit2/ChangeLog (209009 => 209010)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebKit2/ChangeLog        2016-11-28 20:45:27 UTC (rev 209009)
+++ trunk/Source/WebKit2/ChangeLog        2016-11-28 20:46:44 UTC (rev 209010)
</span><span class="lines">@@ -1,3 +1,48 @@
</span><ins>+2016-11-28  Andrew Gold  &lt;agold@apple.com&gt;
+
+        Support for HTML Media Capture API
+        https://bugs.webkit.org/show_bug.cgi?id=43239
+
+        Reviewed by Tim Horton.
+
+        In order to enable media capture on iOS, we must first use the AVFoundation API to 
+        check/request capture permission from the user for Safari. Then, Safari must request
+        permission on behalf of the webpage to use the capture devices. Additionally, Safari
+        must present UI when the capture is taking place, so WebKit needs to notify the client
+        of a capture session beginning and ending. To do this, we added four methods to 
+        WKUIDelegatePrivate to request permission from the user, check for permissions, notify
+        that a capture session has begun, and notify that a capture session has ended. Additionally,
+        we added a private method to WKWebView that allows the client to stop a capture session.
+
+        * UIProcess/API/APIUIClient.h:
+        (API::UIClient::didBeginCaptureSession): Notifies the client of a capture session beginning.
+        (API::UIClient::didEndCaptureSession): Notifies the client of a capture session ending.
+
+        * UIProcess/API/Cocoa/WKUIDelegatePrivate.h: Added new delegate methods to request permission,
+        check for permission, notify of a capture session beginning, and notify of a capture session
+        ending.
+
+        * UIProcess/API/Cocoa/WKWebView.mm:
+        (-[WKWebView _stopMediaCapture]): Cancels a media capture session.
+        * UIProcess/API/Cocoa/WKWebViewPrivate.h:
+
+        * UIProcess/Cocoa/UIDelegate.h:
+        * UIProcess/Cocoa/UIDelegate.mm:
+        (WebKit::UIDelegate::setDelegate): Added the new delegate methods.
+        (WebKit::UIDelegate::UIClient::decidePolicyForUserMediaPermissionRequest):
+        First checks if the user has authorized the client application access capture devices,
+        then uses the WKUIDelegate to request permission for a site from the user.
+        (WebKit::UIDelegate::UIClient::checkUserMediaPermissionForOrigin): Checks the client
+        for permission to access capture devices.
+        (WebKit::UIDelegate::UIClient::didBeginCaptureSession): Notifies the client of a capture
+        session beginning.
+        (WebKit::UIDelegate::UIClient::didEndCaptureSession): Notifies the client of a capture
+        session ending.
+
+        * UIProcess/WebPageProxy.cpp:
+        (WebKit::WebPageProxy::isPlayingMediaDidChange): Calls UIDelegate method to notify the
+        client of a capture session beginning/ending.
+
</ins><span class="cx"> 2016-11-28  Eric Carlson  &lt;eric.carlson@apple.com&gt;
</span><span class="cx"> 
</span><span class="cx">         [MediaStream] Don't request user permission for a device if it has already been granted in the current browsing context
</span></span></pre></div>
<a id="trunkSourceWebKit2UIProcessAPIAPIUIClienth"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebKit2/UIProcess/API/APIUIClient.h (209009 => 209010)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebKit2/UIProcess/API/APIUIClient.h        2016-11-28 20:45:27 UTC (rev 209009)
+++ trunk/Source/WebKit2/UIProcess/API/APIUIClient.h        2016-11-28 20:46:44 UTC (rev 209010)
</span><span class="lines">@@ -150,6 +150,8 @@
</span><span class="cx">     virtual void pinnedStateDidChange(WebKit::WebPageProxy&amp;) { }
</span><span class="cx"> 
</span><span class="cx">     virtual void isPlayingAudioDidChange(WebKit::WebPageProxy&amp;) { }
</span><ins>+    virtual void didBeginCaptureSession() { }
+    virtual void didEndCaptureSession() { }
</ins><span class="cx"> 
</span><span class="cx"> #if ENABLE(MEDIA_SESSION)
</span><span class="cx">     virtual void mediaSessionMetadataDidChange(WebKit::WebPageProxy&amp;, WebKit::WebMediaSessionMetadata*) { }
</span></span></pre></div>
<a id="trunkSourceWebKit2UIProcessAPICocoaWKUIDelegatePrivateh"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebKit2/UIProcess/API/Cocoa/WKUIDelegatePrivate.h (209009 => 209010)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebKit2/UIProcess/API/Cocoa/WKUIDelegatePrivate.h        2016-11-28 20:45:27 UTC (rev 209009)
+++ trunk/Source/WebKit2/UIProcess/API/Cocoa/WKUIDelegatePrivate.h        2016-11-28 20:46:44 UTC (rev 209010)
</span><span class="lines">@@ -60,6 +60,10 @@
</span><span class="cx"> 
</span><span class="cx"> - (void)_webView:(WKWebView *)webView imageOrMediaDocumentSizeChanged:(CGSize)size WK_API_AVAILABLE(macosx(10.12), ios(10.0));
</span><span class="cx"> - (NSDictionary *)_dataDetectionContextForWebView:(WKWebView *)webView WK_API_AVAILABLE(macosx(10.12), ios(10.0));
</span><ins>+- (void)_webView:(WKWebView *)webView requestUserMediaAuthorizationForMicrophone:(BOOL)microphone camera:(BOOL)camera url:(NSURL *)url mainFrameURL:(NSURL *)mainFrameURL decisionHandler:(void (^)(BOOL authorizedMicrophone, BOOL authorizedCamera))decisionHandler WK_API_AVAILABLE(macosx(WK_MAC_TBA), ios(WK_IOS_TBA));
+- (void)_webView:(WKWebView *)webView checkUserMediaPermissionForURL:(NSURL *)url mainFrameURL:(NSURL *)mainFrameURL frameIdentifier:(NSUInteger)frameIdentifier decisionHandler:(void (^)(NSString *salt, BOOL authorized))decisionHandler WK_API_AVAILABLE(macosx(WK_MAC_TBA), ios(WK_IOS_TBA));
+- (void)_webViewDidBeginCaptureSession:(WKWebView *)webView WK_API_AVAILABLE(macosx(WK_MAC_TBA), ios(WK_IOS_TBA));
+- (void)_webViewDidEndCaptureSession:(WKWebView *)webView WK_API_AVAILABLE(macosx(WK_MAC_TBA), ios(WK_IOS_TBA));
</ins><span class="cx"> #if TARGET_OS_IPHONE
</span><span class="cx"> - (BOOL)_webView:(WKWebView *)webView shouldIncludeAppLinkActionsForElement:(_WKActivatedElementInfo *)element WK_API_AVAILABLE(ios(9.0));
</span><span class="cx"> - (NSArray *)_webView:(WKWebView *)webView actionsForElement:(_WKActivatedElementInfo *)element defaultActions:(NSArray&lt;_WKElementAction *&gt; *)defaultActions;
</span></span></pre></div>
<a id="trunkSourceWebKit2UIProcessAPICocoaWKWebViewmm"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebKit2/UIProcess/API/Cocoa/WKWebView.mm (209009 => 209010)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebKit2/UIProcess/API/Cocoa/WKWebView.mm        2016-11-28 20:45:27 UTC (rev 209009)
+++ trunk/Source/WebKit2/UIProcess/API/Cocoa/WKWebView.mm        2016-11-28 20:46:44 UTC (rev 209010)
</span><span class="lines">@@ -4040,6 +4040,11 @@
</span><span class="cx"> #endif
</span><span class="cx"> }
</span><span class="cx"> 
</span><ins>+- (void)_stopMediaCapture
+{
+    _page-&gt;setMuted(WebCore::MediaProducer::CaptureDevicesAreMuted);
+}
+
</ins><span class="cx"> #pragma mark iOS-specific methods
</span><span class="cx"> 
</span><span class="cx"> #if PLATFORM(IOS)
</span></span></pre></div>
<a id="trunkSourceWebKit2UIProcessAPICocoaWKWebViewPrivateh"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebKit2/UIProcess/API/Cocoa/WKWebViewPrivate.h (209009 => 209010)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebKit2/UIProcess/API/Cocoa/WKWebViewPrivate.h        2016-11-28 20:45:27 UTC (rev 209009)
+++ trunk/Source/WebKit2/UIProcess/API/Cocoa/WKWebViewPrivate.h        2016-11-28 20:46:44 UTC (rev 209010)
</span><span class="lines">@@ -258,6 +258,8 @@
</span><span class="cx"> @property (nonatomic, setter=_setFullscreenDelegate:) id&lt;_WKFullscreenDelegate&gt; _fullscreenDelegate WK_API_AVAILABLE(macosx(10.13));
</span><span class="cx"> @property (nonatomic, readonly) BOOL _isInFullscreen WK_API_AVAILABLE(macosx(WK_MAC_TBA));
</span><span class="cx"> 
</span><ins>+- (void)_stopMediaCapture;
+
</ins><span class="cx"> @end
</span><span class="cx"> 
</span><span class="cx"> #if !TARGET_OS_IPHONE
</span></span></pre></div>
<a id="trunkSourceWebKit2UIProcessCocoaUIDelegateh"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebKit2/UIProcess/Cocoa/UIDelegate.h (209009 => 209010)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebKit2/UIProcess/Cocoa/UIDelegate.h        2016-11-28 20:45:27 UTC (rev 209009)
+++ trunk/Source/WebKit2/UIProcess/Cocoa/UIDelegate.h        2016-11-28 20:46:44 UTC (rev 209010)
</span><span class="lines">@@ -89,6 +89,10 @@
</span><span class="cx"> #if PLATFORM(MAC)
</span><span class="cx">         bool runOpenPanel(WebPageProxy*, WebFrameProxy*, const WebCore::SecurityOriginData&amp;, API::OpenPanelParameters*, WebOpenPanelResultListenerProxy*) override;
</span><span class="cx"> #endif
</span><ins>+        bool decidePolicyForUserMediaPermissionRequest(WebKit::WebPageProxy&amp;, WebKit::WebFrameProxy&amp;, API::SecurityOrigin&amp;, API::SecurityOrigin&amp;, WebKit::UserMediaPermissionRequestProxy&amp;) override;
+        bool checkUserMediaPermissionForOrigin(WebKit::WebPageProxy&amp;, WebKit::WebFrameProxy&amp;, API::SecurityOrigin&amp;, API::SecurityOrigin&amp;, WebKit::UserMediaPermissionCheckProxy&amp;) override;
+        void didBeginCaptureSession() override;
+        void didEndCaptureSession() override;
</ins><span class="cx">         void printFrame(WebKit::WebPageProxy*, WebKit::WebFrameProxy*) override;
</span><span class="cx"> #if PLATFORM(IOS)
</span><span class="cx"> #if HAVE(APP_LINKS)
</span><span class="lines">@@ -130,6 +134,10 @@
</span><span class="cx">         bool webViewFullscreenMayReturnToInline : 1;
</span><span class="cx">         bool webViewDidEnterFullscreen : 1;
</span><span class="cx">         bool webViewDidExitFullscreen : 1;
</span><ins>+        bool webViewRequestUserMediaAuthorizationForMicrophoneCameraURLMainFrameURLDecisionHandler : 1;
+        bool webViewCheckUserMediaPermissionForURLMainFrameURLFrameIdentifierDecisionHandler : 1;
+        bool webViewDidBeginCaptureSession : 1;
+        bool webViewDidEndCaptureSession : 1;
</ins><span class="cx"> #if PLATFORM(IOS)
</span><span class="cx"> #if HAVE(APP_LINKS)
</span><span class="cx">         bool webViewShouldIncludeAppLinkActionsForElement : 1;
</span></span></pre></div>
<a id="trunkSourceWebKit2UIProcessCocoaUIDelegatemm"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebKit2/UIProcess/Cocoa/UIDelegate.mm (209009 => 209010)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebKit2/UIProcess/Cocoa/UIDelegate.mm        2016-11-28 20:45:27 UTC (rev 209009)
+++ trunk/Source/WebKit2/UIProcess/Cocoa/UIDelegate.mm        2016-11-28 20:46:44 UTC (rev 209010)
</span><span class="lines">@@ -30,6 +30,8 @@
</span><span class="cx"> 
</span><span class="cx"> #import &quot;CompletionHandlerCallChecker.h&quot;
</span><span class="cx"> #import &quot;NavigationActionData.h&quot;
</span><ins>+#import &quot;UserMediaPermissionCheckProxy.h&quot;
+#import &quot;UserMediaPermissionRequestProxy.h&quot;
</ins><span class="cx"> #import &quot;WKFrameInfoInternal.h&quot;
</span><span class="cx"> #import &quot;WKNavigationActionInternal.h&quot;
</span><span class="cx"> #import &quot;WKOpenPanelParametersInternal.h&quot;
</span><span class="lines">@@ -46,6 +48,17 @@
</span><span class="cx"> #import &lt;WebCore/URL.h&gt;
</span><span class="cx"> #import &lt;wtf/BlockPtr.h&gt;
</span><span class="cx"> 
</span><ins>+#if PLATFORM(IOS)
+#import &lt;AVFoundation/AVCaptureDevice.h&gt;
+#import &lt;AVFoundation/AVMediaFormat.h&gt;
+#import &lt;WebCore/SoftLinking.h&gt;
+
+SOFT_LINK_FRAMEWORK(AVFoundation);
+SOFT_LINK_CLASS(AVFoundation, AVCaptureDevice);
+SOFT_LINK_CONSTANT(AVFoundation, AVMediaTypeAudio, NSString *);
+SOFT_LINK_CONSTANT(AVFoundation, AVMediaTypeVideo, NSString *);
+#endif
+
</ins><span class="cx"> namespace WebKit {
</span><span class="cx"> 
</span><span class="cx"> UIDelegate::UIDelegate(WKWebView *webView)
</span><span class="lines">@@ -101,6 +114,10 @@
</span><span class="cx"> #endif
</span><span class="cx">     m_delegateMethods.webViewActionsForElementDefaultActions = [delegate respondsToSelector:@selector(_webView:actionsForElement:defaultActions:)];
</span><span class="cx">     m_delegateMethods.webViewDidNotHandleTapAsClickAtPoint = [delegate respondsToSelector:@selector(_webView:didNotHandleTapAsClickAtPoint:)];
</span><ins>+    m_delegateMethods.webViewRequestUserMediaAuthorizationForMicrophoneCameraURLMainFrameURLDecisionHandler = [delegate respondsToSelector:@selector(_webView:requestUserMediaAuthorizationForMicrophone:camera:url:mainFrameURL:decisionHandler:)];
+    m_delegateMethods.webViewCheckUserMediaPermissionForURLMainFrameURLFrameIdentifierDecisionHandler = [delegate respondsToSelector:@selector(_webView:checkUserMediaPermissionForURL:mainFrameURL:frameIdentifier:decisionHandler:)];
+    m_delegateMethods.webViewDidBeginCaptureSession = [delegate respondsToSelector:@selector(_webViewDidBeginCaptureSession:)];
+    m_delegateMethods.webViewDidEndCaptureSession = [delegate respondsToSelector:@selector(_webViewDidEndCaptureSession:)];
</ins><span class="cx">     m_delegateMethods.presentingViewControllerForWebView = [delegate respondsToSelector:@selector(_presentingViewControllerForWebView:)];
</span><span class="cx"> #endif
</span><span class="cx">     m_delegateMethods.dataDetectionContextForWebView = [delegate respondsToSelector:@selector(_dataDetectionContextForWebView:)];
</span><span class="lines">@@ -303,6 +320,129 @@
</span><span class="cx"> }
</span><span class="cx"> #endif
</span><span class="cx"> 
</span><ins>+bool UIDelegate::UIClient::decidePolicyForUserMediaPermissionRequest(WebKit::WebPageProxy&amp; page, WebKit::WebFrameProxy&amp; frame, API::SecurityOrigin&amp; userMediaOrigin, API::SecurityOrigin&amp; topLevelOrigin, WebKit::UserMediaPermissionRequestProxy&amp; request)
+{
+    auto delegate = m_uiDelegate.m_delegate.get();
+    if (!delegate || !m_uiDelegate.m_delegateMethods.webViewRequestUserMediaAuthorizationForMicrophoneCameraURLMainFrameURLDecisionHandler) {
+        request.deny(UserMediaPermissionRequestProxy::UserMediaAccessDenialReason::UserMediaDisabled);
+        return true;
+    }
+
+    bool requiresAudio = request.requiresAudio();
+    bool requiresVideo = request.requiresVideo();
+    if (!requiresAudio &amp;&amp; !requiresVideo) {
+        request.deny(UserMediaPermissionRequestProxy::UserMediaAccessDenialReason::NoConstraints);
+        return true;
+    }
+
+    __block WKWebView *webView = m_uiDelegate.m_webView;
+    void (^uiDelegateAuthorizationBlock)(void) = ^ {
+        const WebFrameProxy* mainFrame = frame.page()-&gt;mainFrame();
+        WebCore::URL requestFrameURL(WebCore::URL(), frame.url());
+        WebCore::URL mainFrameURL(WebCore::URL(), mainFrame-&gt;url());
+
+        [(id &lt;WKUIDelegatePrivate&gt;)delegate _webView:webView requestUserMediaAuthorizationForMicrophone:requiresAudio camera:requiresVideo url:requestFrameURL mainFrameURL:mainFrameURL decisionHandler:^(BOOL authorizedMicrophone, BOOL authorizedCamera) {
+            if ((requiresAudio != authorizedMicrophone) || (requiresVideo != authorizedCamera)) {
+                request.deny(UserMediaPermissionRequestProxy::UserMediaAccessDenialReason::PermissionDenied);
+                return;
+            }
+            const String&amp; videoDeviceUID = requiresVideo ? request.videoDeviceUIDs().first() : String();
+            const String&amp; audioDeviceUID = requiresAudio ? request.audioDeviceUIDs().first() : String();
+            request.allow(audioDeviceUID, videoDeviceUID);
+        }];
+    };
+
+#if PLATFORM(IOS)
+    void (^cameraAuthorizationBlock)(void) = ^ {
+        if (requiresVideo) {
+            AVAuthorizationStatus cameraAuthorizationStatus = [getAVCaptureDeviceClass() authorizationStatusForMediaType:getAVMediaTypeVideo()];
+            switch (cameraAuthorizationStatus) {
+            case AVAuthorizationStatusDenied:
+            case AVAuthorizationStatusRestricted:
+                request.deny(UserMediaPermissionRequestProxy::UserMediaAccessDenialReason::PermissionDenied);
+                return;
+            case AVAuthorizationStatusNotDetermined:
+                [getAVCaptureDeviceClass() requestAccessForMediaType:getAVMediaTypeVideo() completionHandler:^(BOOL authorized) {
+                    if (!authorized) {
+                        request.deny(UserMediaPermissionRequestProxy::UserMediaAccessDenialReason::PermissionDenied);
+                        return;
+                    }
+                    uiDelegateAuthorizationBlock();
+                }];
+                break;
+            default:
+                uiDelegateAuthorizationBlock();
+            }
+        } else
+            uiDelegateAuthorizationBlock();
+    };
+
+    if (requiresAudio) {
+        AVAuthorizationStatus microphoneAuthorizationStatus = [getAVCaptureDeviceClass() authorizationStatusForMediaType:getAVMediaTypeAudio()];
+        switch (microphoneAuthorizationStatus) {
+        case AVAuthorizationStatusDenied:
+        case AVAuthorizationStatusRestricted:
+            request.deny(UserMediaPermissionRequestProxy::UserMediaAccessDenialReason::PermissionDenied);
+            return true;
+        case AVAuthorizationStatusNotDetermined:
+            [getAVCaptureDeviceClass() requestAccessForMediaType:getAVMediaTypeAudio() completionHandler:^(BOOL authorized) {
+                if (!authorized) {
+                    request.deny(UserMediaPermissionRequestProxy::UserMediaAccessDenialReason::PermissionDenied);
+                    return;
+                }
+                cameraAuthorizationBlock();
+            }];
+            break;
+        default:
+            cameraAuthorizationBlock();
+        }
+    } else
+        cameraAuthorizationBlock();
+#else
+    uiDelegateAuthorizationBlock();
+#endif
+
+    return true;
+}
+
+bool UIDelegate::UIClient::checkUserMediaPermissionForOrigin(WebKit::WebPageProxy&amp; page, WebKit::WebFrameProxy&amp; frame, API::SecurityOrigin&amp; userMediaOrigin, API::SecurityOrigin&amp; topLevelOrigin, WebKit::UserMediaPermissionCheckProxy&amp; request)
+{
+    auto delegate = m_uiDelegate.m_delegate.get();
+    if (!delegate || !m_uiDelegate.m_delegateMethods.webViewCheckUserMediaPermissionForURLMainFrameURLFrameIdentifierDecisionHandler) {
+        request.setUserMediaAccessInfo(String(), false);
+        return true;
+    }
+
+    WKWebView *webView = m_uiDelegate.m_webView;
+    const WebFrameProxy* mainFrame = frame.page()-&gt;mainFrame();
+    WebCore::URL requestFrameURL(WebCore::URL(), frame.url());
+    WebCore::URL mainFrameURL(WebCore::URL(), mainFrame-&gt;url());
+
+    [(id &lt;WKUIDelegatePrivate&gt;)delegate _webView:webView checkUserMediaPermissionForURL:requestFrameURL mainFrameURL:mainFrameURL frameIdentifier:frame.frameID() decisionHandler:^(NSString *salt, BOOL authorized) {
+        request.setUserMediaAccessInfo(String(salt), authorized);
+    }];
+
+    return true;
+}
+
+void UIDelegate::UIClient::didBeginCaptureSession()
+{
+    auto delegate = m_uiDelegate.m_delegate.get();
+    if (!delegate || !m_uiDelegate.m_delegateMethods.webViewDidBeginCaptureSession)
+        return;
+
+    [(id &lt;WKUIDelegatePrivate&gt;)delegate _webViewDidBeginCaptureSession:m_uiDelegate.m_webView];
+}
+
+void UIDelegate::UIClient::didEndCaptureSession()
+{
+    auto delegate = m_uiDelegate.m_delegate.get();
+    if (!delegate || !m_uiDelegate.m_delegateMethods.webViewDidEndCaptureSession)
+        return;
+
+    [(id &lt;WKUIDelegatePrivate&gt;)delegate _webViewDidEndCaptureSession:m_uiDelegate.m_webView];
+}
+
</ins><span class="cx"> void UIDelegate::UIClient::reachedApplicationCacheOriginQuota(WebPageProxy*, const WebCore::SecurityOrigin&amp; securityOrigin, uint64_t currentQuota, uint64_t totalBytesNeeded, Function&lt;void (unsigned long long)&gt;&amp;&amp; completionHandler)
</span><span class="cx"> {
</span><span class="cx">     if (!m_uiDelegate.m_delegateMethods.webViewDecideWebApplicationCacheQuotaForSecurityOriginCurrentQuotaTotalBytesNeeded) {
</span></span></pre></div>
<a id="trunkSourceWebKit2UIProcessWebPageProxycpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebKit2/UIProcess/WebPageProxy.cpp (209009 => 209010)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebKit2/UIProcess/WebPageProxy.cpp        2016-11-28 20:45:27 UTC (rev 209009)
+++ trunk/Source/WebKit2/UIProcess/WebPageProxy.cpp        2016-11-28 20:46:44 UTC (rev 209010)
</span><span class="lines">@@ -6409,6 +6409,13 @@
</span><span class="cx">     if (state == m_mediaState)
</span><span class="cx">         return;
</span><span class="cx"> 
</span><ins>+    WebCore::MediaProducer::MediaStateFlags oldMediaStateHasActiveCapture = m_mediaState &amp; (WebCore::MediaProducer::HasActiveAudioCaptureDevice | WebCore::MediaProducer::HasActiveVideoCaptureDevice);
+    WebCore::MediaProducer::MediaStateFlags newMediaStateHasActiveCapture = state &amp; (WebCore::MediaProducer::HasActiveAudioCaptureDevice | WebCore::MediaProducer::HasActiveVideoCaptureDevice);
+    if (!oldMediaStateHasActiveCapture &amp;&amp; newMediaStateHasActiveCapture)
+        m_uiClient-&gt;didBeginCaptureSession();
+    if (oldMediaStateHasActiveCapture &amp;&amp; !newMediaStateHasActiveCapture)
+        m_uiClient-&gt;didEndCaptureSession();
+
</ins><span class="cx">     MediaProducer::MediaStateFlags playingMediaMask = MediaProducer::IsPlayingAudio | MediaProducer::IsPlayingVideo;
</span><span class="cx">     MediaProducer::MediaStateFlags oldState = m_mediaState;
</span><span class="cx">     m_mediaState = state;
</span></span></pre>
</div>
</div>

</body>
</html>