[MediaStream] defer resolution of getUserMedia promise made in a background tab
authoreric.carlson@apple.com <eric.carlson@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Fri, 11 Nov 2016 21:45:21 +0000 (21:45 +0000)
committereric.carlson@apple.com <eric.carlson@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Fri, 11 Nov 2016 21:45:21 +0000 (21:45 +0000)
https://bugs.webkit.org/show_bug.cgi?id=164643
<rdar://problem/29048317>

Reviewed by Brady Eidson.

Source/WebCore:

Test: fast/mediastream/get-user-media-background-tab.html

Do not start producing data when the document does not allow media
to start playing. Instead, register with the document for a callback
when playback is allowed and start then.
* Modules/mediastream/MediaStream.cpp:
(WebCore::MediaStream::~MediaStream):
(WebCore::MediaStream::mediaCanStart):
(WebCore::MediaStream::startProducingData):
(WebCore::MediaStream::stopProducingData):
(WebCore::MediaStream::pageMutedStateDidChange):
* Modules/mediastream/MediaStream.h:

* Modules/webaudio/AudioContext.cpp:
(WebCore::AudioContext::mediaCanStart): Deal with API change.
* Modules/webaudio/AudioContext.h:

* html/HTMLMediaElement.cpp:
(WebCore::HTMLMediaElement::mediaCanStart): Ditto.
* html/HTMLMediaElement.h:
* page/MediaCanStartListener.h:

* page/Page.cpp:
(WebCore::Page::takeAnyMediaCanStartListener): Return the listener and document.
(WebCore::Page::setCanStartMedia): Pass the document to the listener.
* page/Page.h:

Source/WebKit2:

Do not ask for user for access to capture devices when the document does not
allow media to play, wait until playback is allowed.

* WebProcess/MediaStream/UserMediaPermissionRequestManager.cpp:
(WebKit::UserMediaPermissionRequestManager::startUserMediaRequest):
(WebKit::UserMediaPermissionRequestManager::sendUserMediaRequest):
(WebKit::UserMediaPermissionRequestManager::mediaCanStart):
(WebKit::UserMediaPermissionRequestManager::grantUserMediaDevicesSandboxExtension):
* WebProcess/MediaStream/UserMediaPermissionRequestManager.h:
* WebProcess/Plugins/PluginView.cpp:
(WebKit::PluginView::mediaCanStart):
* WebProcess/Plugins/PluginView.h:

LayoutTests:

* fast/mediastream/get-user-media-background-tab-expected.txt: Added.
* fast/mediastream/get-user-media-background-tab.html: Added.

git-svn-id: https://svn.webkit.org/repository/webkit/trunk@208606 268f45cc-cd09-0410-ab3c-d52691b4dbfc

18 files changed:
LayoutTests/ChangeLog
LayoutTests/fast/mediastream/get-user-media-background-tab-expected.txt [new file with mode: 0644]
LayoutTests/fast/mediastream/get-user-media-background-tab.html [new file with mode: 0644]
Source/WebCore/ChangeLog
Source/WebCore/Modules/mediastream/MediaStream.cpp
Source/WebCore/Modules/mediastream/MediaStream.h
Source/WebCore/Modules/webaudio/AudioContext.cpp
Source/WebCore/Modules/webaudio/AudioContext.h
Source/WebCore/html/HTMLMediaElement.cpp
Source/WebCore/html/HTMLMediaElement.h
Source/WebCore/page/MediaCanStartListener.h
Source/WebCore/page/Page.cpp
Source/WebCore/page/Page.h
Source/WebKit2/ChangeLog
Source/WebKit2/WebProcess/MediaStream/UserMediaPermissionRequestManager.cpp
Source/WebKit2/WebProcess/MediaStream/UserMediaPermissionRequestManager.h
Source/WebKit2/WebProcess/Plugins/PluginView.cpp
Source/WebKit2/WebProcess/Plugins/PluginView.h

index 0d00bc5..d919771 100644 (file)
@@ -1,3 +1,14 @@
+2016-11-11  Eric Carlson  <eric.carlson@apple.com>
+
+        [MediaStream] defer resolution of getUserMedia promise made in a background tab
+        https://bugs.webkit.org/show_bug.cgi?id=164643
+        <rdar://problem/29048317>
+
+        Reviewed by Brady Eidson.
+
+        * fast/mediastream/get-user-media-background-tab-expected.txt: Added.
+        * fast/mediastream/get-user-media-background-tab.html: Added.
+
 2016-11-10  Jiewen Tan  <jiewen_tan@apple.com>
 
         Rename CryptoKeyUsage to CryptoKeyUsageBitmap and CryptoKey::Usage to CryptoKeyUsage
diff --git a/LayoutTests/fast/mediastream/get-user-media-background-tab-expected.txt b/LayoutTests/fast/mediastream/get-user-media-background-tab-expected.txt
new file mode 100644 (file)
index 0000000..fe93392
--- /dev/null
@@ -0,0 +1,34 @@
+Tests getUserMedia called from a background thread.
+
+On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
+
+
+tabState = 'background'
+PASS navigator.mediaDevices.getUserMedia({audio:true}).then(gotStream).catch(fail) did not throw exception.
+PASS navigator.mediaDevices.getUserMedia({audio:true}).then(gotStream).catch(fail) did not throw exception.
+PASS navigator.mediaDevices.getUserMedia({audio:true}).then(gotStream).catch(fail) did not throw exception.
+PASS navigator.mediaDevices.getUserMedia({audio:true}).then(gotStream).catch(fail) did not throw exception.
+
+** timer fired **
+PASS tabState is 'background'
+tabState = 'foreground'
+
+** getUserMedia() promise resolved **
+PASS tabState is 'foreground'
+PASS stream.getAudioTracks().length is 1
+
+** getUserMedia() promise resolved **
+PASS tabState is 'foreground'
+PASS stream.getAudioTracks().length is 1
+
+** getUserMedia() promise resolved **
+PASS tabState is 'foreground'
+PASS stream.getAudioTracks().length is 1
+
+** getUserMedia() promise resolved **
+PASS tabState is 'foreground'
+PASS stream.getAudioTracks().length is 1
+PASS successfullyParsed is true
+
+TEST COMPLETE
+
diff --git a/LayoutTests/fast/mediastream/get-user-media-background-tab.html b/LayoutTests/fast/mediastream/get-user-media-background-tab.html
new file mode 100644 (file)
index 0000000..3efe0d2
--- /dev/null
@@ -0,0 +1,56 @@
+<!DOCTYPE html>
+<html>
+    <head>
+        <script src="../../resources/js-test-pre.js"></script>
+        <script>
+            let tabState;
+            let streamCount = 4;
+            let streams = 0;
+
+            function gotStream(s)
+            {
+                debug('<br>** getUserMedia() promise resolved **')
+                shouldBe('tabState', "'foreground'");
+                stream = s;
+                shouldBe('stream.getAudioTracks().length', '1');
+                if (++streams == streamCount)
+                    finishJSTest();
+            }
+
+            function fail(error)
+            {
+                testFailed(`getUserMedia() failed, error = ${error}`);
+                finishJSTest();
+            }
+
+            function checkState()
+            {
+                debug('<br>** timer fired **')
+                shouldBe('tabState', "'background'");
+                evalAndLog(`tabState = 'foreground'`);
+                if (internals)
+                    internals.settings.setCanStartMedia(true);
+            }
+
+            function start()
+            {
+                description("Tests getUserMedia called from a background thread.");
+                evalAndLog(`tabState = 'background'`);
+                if (window.testRunner) {
+                    internals.settings.setCanStartMedia(false);
+                    testRunner.setUserMediaPermission(true);
+                }
+                for (var i = 0; i < streamCount; i++)
+                    shouldNotThrow('navigator.mediaDevices.getUserMedia({audio:true}).then(gotStream).catch(fail)');
+                setTimeout(checkState, 200);
+            }
+
+            window.jsTestIsAsync = true;
+            window.successfullyParsed = true;
+
+        </script>
+        <script src="../../resources/js-test-post.js"></script>
+    </head>
+    <body onload="start()">
+    </body>
+</html>
index ecca0fb..e29b3f1 100644 (file)
@@ -1,3 +1,38 @@
+2016-11-11  Eric Carlson  <eric.carlson@apple.com>
+
+        [MediaStream] defer resolution of getUserMedia promise made in a background tab
+        https://bugs.webkit.org/show_bug.cgi?id=164643
+        <rdar://problem/29048317>
+
+        Reviewed by Brady Eidson.
+
+        Test: fast/mediastream/get-user-media-background-tab.html
+
+        Do not start producing data when the document does not allow media
+        to start playing. Instead, register with the document for a callback 
+        when playback is allowed and start then.
+        * Modules/mediastream/MediaStream.cpp:
+        (WebCore::MediaStream::~MediaStream):
+        (WebCore::MediaStream::mediaCanStart):
+        (WebCore::MediaStream::startProducingData):
+        (WebCore::MediaStream::stopProducingData):
+        (WebCore::MediaStream::pageMutedStateDidChange):
+        * Modules/mediastream/MediaStream.h:
+
+        * Modules/webaudio/AudioContext.cpp:
+        (WebCore::AudioContext::mediaCanStart): Deal with API change.
+        * Modules/webaudio/AudioContext.h:
+
+        * html/HTMLMediaElement.cpp:
+        (WebCore::HTMLMediaElement::mediaCanStart): Ditto.
+        * html/HTMLMediaElement.h:
+        * page/MediaCanStartListener.h:
+
+        * page/Page.cpp:
+        (WebCore::Page::takeAnyMediaCanStartListener): Return the listener and document.
+        (WebCore::Page::setCanStartMedia): Pass the document to the listener.
+        * page/Page.h:
+
 2016-11-11  Zalan Bujtas  <zalan@apple.com>
 
         RenderFlowThread's containing block cache should be invalidated before calling styleDidChange.
index 7508a03..b87ff4e 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * Copyright (C) 2011 Google Inc. All rights reserved.
  * Copyright (C) 2011, 2012, 2015 Ericsson AB. All rights reserved.
- * Copyright (C) 2013-2015 Apple Inc. All rights reserved.
+ * Copyright (C) 2013-2016 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
@@ -34,6 +34,7 @@
 #include "Event.h"
 #include "EventNames.h"
 #include "ExceptionCode.h"
+#include "Logging.h"
 #include "MediaStreamRegistry.h"
 #include "MediaStreamTrackEvent.h"
 #include "Page.h"
@@ -111,8 +112,11 @@ MediaStream::~MediaStream()
     m_private->removeObserver(*this);
     for (auto& track : m_trackSet.values())
         track->removeObserver(this);
-    if (Document* document = this->document())
+    if (Document* document = this->document()) {
         document->removeAudioProducer(this);
+        if (m_isWaitingUntilMediaCanStart)
+            document->removeMediaCanStartListener(this);
+    }
 }
 
 RefPtr<MediaStream> MediaStream::clone()
@@ -247,6 +251,41 @@ void MediaStream::setIsActive(bool active)
     statusDidChange();
 }
 
+void MediaStream::mediaCanStart(Document& document)
+{
+    ASSERT_UNUSED(document, &document == this->document());
+    ASSERT(m_isWaitingUntilMediaCanStart);
+    if (m_isWaitingUntilMediaCanStart) {
+        m_isWaitingUntilMediaCanStart = false;
+        startProducingData();
+    }
+}
+
+void MediaStream::startProducingData()
+{
+    Document* document = this->document();
+    if (!document || !document->page())
+        return;
+
+    // If we can't start a load right away, start it later.
+    if (!document->page()->canStartMedia()) {
+        LOG(Media, "MediaStream::startProducingData(%p) - not allowed to start in background, waiting", this);
+        if (m_isWaitingUntilMediaCanStart)
+            return;
+
+        m_isWaitingUntilMediaCanStart = true;
+        document->addMediaCanStartListener(this);
+        return;
+    }
+
+    m_private->startProducingData();
+}
+
+void MediaStream::stopProducingData()
+{
+    m_private->stopProducingData();
+}
+
 void MediaStream::pageMutedStateDidChange()
 {
     if (!m_isActive)
@@ -262,9 +301,9 @@ void MediaStream::pageMutedStateDidChange()
 
     m_externallyMuted = pageMuted;
     if (pageMuted)
-        m_private->stopProducingData();
+        stopProducingData();
     else
-        m_private->startProducingData();
+        startProducingData();
 }
 
 MediaProducer::MediaStateFlags MediaStream::mediaState() const
index 8f8ad98..00e1f87 100644 (file)
@@ -33,6 +33,7 @@
 #include "ContextDestructionObserver.h"
 #include "EventTarget.h"
 #include "ExceptionBase.h"
+#include "MediaCanStartListener.h"
 #include "MediaProducer.h"
 #include "MediaStreamPrivate.h"
 #include "MediaStreamTrack.h"
@@ -47,7 +48,15 @@ namespace WebCore {
 
 class Document;
 
-class MediaStream final : public URLRegistrable, public EventTargetWithInlineData, public ContextDestructionObserver, public MediaStreamTrack::Observer, public MediaStreamPrivate::Observer, private MediaProducer, public RefCounted<MediaStream> {
+class MediaStream final
+    : public URLRegistrable
+    , public EventTargetWithInlineData
+    , public ContextDestructionObserver
+    , public MediaStreamTrack::Observer
+    , public MediaStreamPrivate::Observer
+    , private MediaProducer
+    , private MediaCanStartListener
+    , public RefCounted<MediaStream> {
 public:
     class Observer {
     public:
@@ -78,6 +87,9 @@ public:
 
     MediaStreamPrivate* privateStream() const { return m_private.get(); }
 
+    void startProducingData();
+    void stopProducingData();
+
     // EventTarget
     EventTargetInterface eventTargetInterface() const final { return MediaStreamEventTargetInterfaceType; }
     ScriptExecutionContext* scriptExecutionContext() const final { return ContextDestructionObserver::scriptExecutionContext(); }
@@ -118,6 +130,9 @@ private:
     void pageMutedStateDidChange() final;
     MediaProducer::MediaStateFlags mediaState() const final;
 
+    // MediaCanStartListener
+    void mediaCanStart(Document&) final;
+
     bool internalAddTrack(Ref<MediaStreamTrack>&&, StreamModifier);
     bool internalRemoveTrack(const String&, StreamModifier);
 
@@ -142,6 +157,7 @@ private:
     bool m_isActive { false };
     bool m_isMuted { true };
     bool m_externallyMuted { false };
+    bool m_isWaitingUntilMediaCanStart { false };
 };
 
 } // namespace WebCore
index 504c346..4c1e8a8 100644 (file)
@@ -957,8 +957,9 @@ void AudioContext::startRendering()
     setState(State::Running);
 }
 
-void AudioContext::mediaCanStart()
+void AudioContext::mediaCanStart(Document& document)
 {
+    ASSERT_UNUSED(document, &document == this->document());
     removeBehaviorRestriction(AudioContext::RequirePageConsentForAudioStartRestriction);
     mayResumePlayback(true);
 }
index c3dae43..5c1e24d 100644 (file)
@@ -284,7 +284,7 @@ private:
 
     void scheduleNodeDeletion();
 
-    void mediaCanStart() override;
+    void mediaCanStart(Document&) override;
 
     // MediaProducer
     MediaProducer::MediaStateFlags mediaState() const override;
index 4422b38..17d6f95 100644 (file)
@@ -5664,8 +5664,9 @@ unsigned HTMLMediaElement::webkitVideoDecodedByteCount() const
 }
 #endif
 
-void HTMLMediaElement::mediaCanStart()
+void HTMLMediaElement::mediaCanStart(Document& document)
 {
+    ASSERT_UNUSED(document, &document == &this->document());
     LOG(Media, "HTMLMediaElement::mediaCanStart(%p) - m_isWaitingUntilMediaCanStart = %s, m_pausedInternal = %s",
         this, boolString(m_isWaitingUntilMediaCanStart), boolString(m_pausedInternal) );
 
index 1daee93..58f1a3a 100644 (file)
@@ -727,7 +727,7 @@ private:
 
     void setPlaybackRateInternal(double);
 
-    void mediaCanStart() override;
+    void mediaCanStart(Document&) final;
 
     void invalidateCachedTime() const;
     void refreshCachedTime() const;
index 6cd9aec..890e441 100644 (file)
 
 namespace WebCore {
 
+class Document;
+
 class MediaCanStartListener {
 public:
-    virtual void mediaCanStart() = 0;
+    virtual void mediaCanStart(Document&) = 0;
 protected:
     virtual ~MediaCanStartListener() { }
 };
index 70d0e1e..625fc5f 100644 (file)
@@ -555,15 +555,15 @@ bool Page::showAllPlugins() const
     return false;
 }
 
-inline MediaCanStartListener* Page::takeAnyMediaCanStartListener()
+inline Optional<std::pair<MediaCanStartListener&, Document&>>  Page::takeAnyMediaCanStartListener()
 {
     for (Frame* frame = &mainFrame(); frame; frame = frame->tree().traverseNext()) {
         if (!frame->document())
             continue;
         if (MediaCanStartListener* listener = frame->document()->takeAnyMediaCanStartListener())
-            return listener;
+            return { { *listener, *frame->document() } };
     }
-    return 0;
+    return Nullopt;
 }
 
 void Page::setCanStartMedia(bool canStartMedia)
@@ -574,10 +574,10 @@ void Page::setCanStartMedia(bool canStartMedia)
     m_canStartMedia = canStartMedia;
 
     while (m_canStartMedia) {
-        MediaCanStartListener* listener = takeAnyMediaCanStartListener();
+        auto listener = takeAnyMediaCanStartListener();
         if (!listener)
             break;
-        listener->mediaCanStart();
+        listener->first.mediaCanStart(listener->second);
     }
 }
 
index 065aa86..23a359e 100644 (file)
@@ -549,7 +549,7 @@ private:
 
     unsigned findMatchesForText(const String&, FindOptions, unsigned maxMatchCount, ShouldHighlightMatches, ShouldMarkMatches);
 
-    MediaCanStartListener* takeAnyMediaCanStartListener();
+    Optional<std::pair<MediaCanStartListener&, Document&>> takeAnyMediaCanStartListener();
 
     Vector<Ref<PluginViewBase>> pluginViews();
 
index f72618d..81a7fa3 100644 (file)
@@ -1,3 +1,24 @@
+2016-11-11  Eric Carlson  <eric.carlson@apple.com>
+
+        [MediaStream] defer resolution of getUserMedia promise made in a background tab
+        https://bugs.webkit.org/show_bug.cgi?id=164643
+        <rdar://problem/29048317>
+
+        Reviewed by Brady Eidson.
+
+        Do not ask for user for access to capture devices when the document does not
+        allow media to play, wait until playback is allowed.
+
+        * WebProcess/MediaStream/UserMediaPermissionRequestManager.cpp:
+        (WebKit::UserMediaPermissionRequestManager::startUserMediaRequest):
+        (WebKit::UserMediaPermissionRequestManager::sendUserMediaRequest):
+        (WebKit::UserMediaPermissionRequestManager::mediaCanStart):
+        (WebKit::UserMediaPermissionRequestManager::grantUserMediaDevicesSandboxExtension):
+        * WebProcess/MediaStream/UserMediaPermissionRequestManager.h:
+        * WebProcess/Plugins/PluginView.cpp:
+        (WebKit::PluginView::mediaCanStart):
+        * WebProcess/Plugins/PluginView.h:
+
 2016-11-11  Darin Adler  <darin@apple.com>
 
         Move Node from ExceptionCode to ExceptionOr
index 0c805ad..023439f 100644 (file)
@@ -60,6 +60,27 @@ void UserMediaPermissionRequestManager::startUserMediaRequest(UserMediaRequest&
     Document* document = request.document();
     Frame* frame = document ? document->frame() : nullptr;
 
+    if (!frame || !document->page()) {
+        request.deny(UserMediaRequest::OtherFailure, emptyString());
+        return;
+    }
+
+    if (document->page()->canStartMedia()) {
+        sendUserMediaRequest(request);
+        return;
+    }
+
+    auto& pendingRequests = m_blockedRequests.add(document, Vector<RefPtr<UserMediaRequest>>()).iterator->value;
+    if (pendingRequests.isEmpty())
+        document->addMediaCanStartListener(this);
+    pendingRequests.append(&request);
+}
+
+void UserMediaPermissionRequestManager::sendUserMediaRequest(UserMediaRequest& request)
+{
+    Document* document = request.document();
+    Frame* frame = document ? document->frame() : nullptr;
+
     if (!frame) {
         request.deny(UserMediaRequest::OtherFailure, emptyString());
         return;
@@ -83,6 +104,38 @@ void UserMediaPermissionRequestManager::cancelUserMediaRequest(UserMediaRequest&
     if (!requestID)
         return;
     m_idToUserMediaRequestMap.remove(requestID);
+    removeMediaRequestFromMaps(request);
+}
+
+void UserMediaPermissionRequestManager::mediaCanStart(Document& document)
+{
+    auto pendingRequests = m_blockedRequests.take(&document);
+    while (!pendingRequests.isEmpty()) {
+        if (!document.page()->canStartMedia()) {
+            m_blockedRequests.add(&document, pendingRequests);
+            document.addMediaCanStartListener(this);
+            break;
+        }
+
+        sendUserMediaRequest(*pendingRequests.takeLast());
+    }
+}
+
+void UserMediaPermissionRequestManager::removeMediaRequestFromMaps(UserMediaRequest& request)
+{
+    auto pendingRequests = m_blockedRequests.take(request.document());
+    for (auto& pendingRequest : pendingRequests) {
+        if (&request != pendingRequest.get())
+            continue;
+
+        if (pendingRequests.isEmpty())
+            request.document()->removeMediaCanStartListener(this);
+        else
+            m_blockedRequests.add(request.document(), pendingRequests);
+        break;
+    }
+
+    m_userMediaRequestToIDMap.remove(&request);
 }
 
 void UserMediaPermissionRequestManager::userMediaAccessWasGranted(uint64_t requestID, const String& audioDeviceUID, const String& videoDeviceUID)
@@ -90,7 +143,7 @@ void UserMediaPermissionRequestManager::userMediaAccessWasGranted(uint64_t reque
     auto request = m_idToUserMediaRequestMap.take(requestID);
     if (!request)
         return;
-    m_userMediaRequestToIDMap.remove(request);
+    removeMediaRequestFromMaps(*request);
 
     request->allow(audioDeviceUID, videoDeviceUID);
 }
@@ -100,7 +153,7 @@ void UserMediaPermissionRequestManager::userMediaAccessWasDenied(uint64_t reques
     auto request = m_idToUserMediaRequestMap.take(requestID);
     if (!request)
         return;
-    m_userMediaRequestToIDMap.remove(request);
+    removeMediaRequestFromMaps(*request);
 
     request->deny(reason, invalidConstraint);
 }
@@ -150,7 +203,7 @@ void UserMediaPermissionRequestManager::grantUserMediaDevicesSandboxExtension(co
     ASSERT(m_userMediaDeviceSandboxExtensions.size() <= 2);
 
     for (size_t i = 0; i < sandboxExtensionHandles.size(); i++) {
-        if (RefPtr<SandboxExtension> extension = SandboxExtension::create(sandboxExtensionHandles[i])) {
+        if (auto extension = SandboxExtension::create(sandboxExtensionHandles[i])) {
             extension->consume();
             m_userMediaDeviceSandboxExtensions.append(extension.release());
         }
index 87d3c63..318aaf2 100644 (file)
@@ -23,6 +23,7 @@
 #if ENABLE(MEDIA_STREAM)
 
 #include "SandboxExtension.h"
+#include <WebCore/MediaCanStartListener.h>
 #include <WebCore/MediaConstraints.h>
 #include <WebCore/MediaDevicesEnumerationRequest.h>
 #include <WebCore/UserMediaClient.h>
@@ -35,7 +36,8 @@ namespace WebKit {
 
 class WebPage;
 
-class UserMediaPermissionRequestManager {
+class UserMediaPermissionRequestManager
+    : private WebCore::MediaCanStartListener {
 public:
     explicit UserMediaPermissionRequestManager(WebPage&);
     ~UserMediaPermissionRequestManager();
@@ -52,6 +54,13 @@ public:
     void grantUserMediaDevicesSandboxExtension(const SandboxExtension::HandleArray&);
 
 private:
+    void sendUserMediaRequest(WebCore::UserMediaRequest&);
+
+    // WebCore::MediaCanStartListener
+    void mediaCanStart(WebCore::Document&) override;
+
+    void removeMediaRequestFromMaps(WebCore::UserMediaRequest&);
+
     WebPage& m_page;
 
     HashMap<uint64_t, RefPtr<WebCore::UserMediaRequest>> m_idToUserMediaRequestMap;
@@ -61,6 +70,8 @@ private:
     HashMap<RefPtr<WebCore::MediaDevicesEnumerationRequest>, uint64_t> m_mediaDevicesEnumerationRequestToIDMap;
 
     Vector<RefPtr<SandboxExtension>> m_userMediaDeviceSandboxExtensions;
+
+    HashMap<RefPtr<WebCore::Document>, Vector<RefPtr<WebCore::UserMediaRequest>>> m_blockedRequests;
 };
 
 } // namespace WebKit
index aecb322..a0d8ab8 100644 (file)
@@ -1371,7 +1371,7 @@ void PluginView::setFocus(bool hasFocus)
     m_plugin->setFocus(hasFocus);
 }
 
-void PluginView::mediaCanStart()
+void PluginView::mediaCanStart(WebCore::Document&)
 {
     ASSERT(m_isWaitingUntilMediaCanStart);
     m_isWaitingUntilMediaCanStart = false;
index 60bea00..007583c 100644 (file)
@@ -184,7 +184,7 @@ private:
     void clipRectChanged() override;
 
     // WebCore::MediaCanStartListener
-    void mediaCanStart() override;
+    void mediaCanStart(WebCore::Document&) override;
 
     // WebCore::MediaProducer
     MediaProducer::MediaStateFlags mediaState() const override { return m_pluginIsPlayingAudio ? MediaProducer::IsPlayingAudio : MediaProducer::IsNotPlaying; }