[MediaStream] Move capture device monitoring to WebKit
authoreric.carlson@apple.com <eric.carlson@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Mon, 20 Aug 2018 18:10:22 +0000 (18:10 +0000)
committereric.carlson@apple.com <eric.carlson@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Mon, 20 Aug 2018 18:10:22 +0000 (18:10 +0000)
https://bugs.webkit.org/show_bug.cgi?id=188521
<rdar://problem/43251787>

Reviewed by Youenn Fablet.

Source/WebCore:

No new tests, updated fast/mediastream/device-change-event-2.html for the changes.

* Modules/mediastream/MediaDevices.cpp:
(WebCore::MediaDevices::MediaDevices): Device change listener is added in addEventListener.
(WebCore::MediaDevices::stop): Device change listener is on the user media controller.
(WebCore::MediaDevices::addEventListener): Add the device change listener only once the first
event handler is added.
* Modules/mediastream/MediaDevices.h:

* Modules/mediastream/UserMediaClient.h:
* Modules/mediastream/UserMediaController.h:
(WebCore::UserMediaController::addDeviceChangeObserver): Pass through to the client.
(WebCore::UserMediaController::removeDeviceChangeObserver): Ditto.

* platform/mediastream/CaptureDeviceManager.cpp:
(CaptureDeviceManager::deviceChanged): Notify RealtimeMediaSourceCenter.
(nextObserverToken): Deleted.
(CaptureDeviceManager::addCaptureDeviceChangedObserver): Deleted.
(CaptureDeviceManager::removeCaptureDeviceChangedObserver): Deleted.
* platform/mediastream/CaptureDeviceManager.h:

* platform/mediastream/RealtimeMediaSourceCenter.cpp:
(WebCore::RealtimeMediaSourceCenter::setDevicesChangedObserver):
(WebCore::RealtimeMediaSourceCenter::captureDevicesChanged):
(WebCore::observerMap): Deleted.
(WebCore::RealtimeMediaSourceCenter::addDevicesChangedObserver): Deleted.
(WebCore::RealtimeMediaSourceCenter::removeDevicesChangedObserver): Deleted.
* platform/mediastream/RealtimeMediaSourceCenter.h:

* platform/mediastream/ios/AVAudioSessionCaptureDeviceManager.mm:
(WebCore::AVAudioSessionCaptureDeviceManager::refreshAudioCaptureDevices): Call base class.

* platform/mediastream/mac/AVCaptureDeviceManager.mm:
(WebCore::AVCaptureDeviceManager::deviceConnected): Ditto.
(WebCore::AVCaptureDeviceManager::deviceDisconnected): Ditto.

* platform/mediastream/mac/CoreAudioCaptureDeviceManager.cpp:
(WebCore::deviceHasInputStreams): Drive-by fix, check the number of buffers to see if the
device has input streams.
(WebCore::CoreAudioCaptureDeviceManager::coreAudioCaptureDevices): Use new bool parameter
added to refreshAudioCaptureDevices so we won't trigger a device change event on the first scan.
(WebCore::CoreAudioCaptureDeviceManager::refreshAudioCaptureDevices): Add param.
(WebCore::CoreAudioCaptureDeviceManager::devicesChanged): Use new param.
* platform/mediastream/mac/CoreAudioCaptureDeviceManager.h:

* platform/mock/MockRealtimeMediaSourceCenter.cpp:
(WebCore::MockRealtimeMediaSourceCenter::setDevices): Don't need to call captureDevicesChanged,
it is done in the UI process.
(WebCore::MockRealtimeMediaSourceCenter::addDevice): Ditto.
(WebCore::MockRealtimeMediaSourceCenter::removeDevice): Ditto.

* testing/InternalSettings.cpp:
(WebCore::InternalSettings::setPageIsFocusedAndActive): New, used by updated test.
* testing/Internals.h:
* testing/Internals.idl:

Source/WebKit:

* UIProcess/UserMediaPermissionRequestManagerProxy.cpp:
(WebKit::UserMediaPermissionRequestManagerProxy::captureDevicesChanged): Notify as appropriate.
(WebKit::UserMediaPermissionRequestManagerProxy::viewIsBecomingVisible): Change name from
viewIsBecomingVisible. Call captureDevicesChanged if a change happened when not visible.
(WebKit::UserMediaPermissionRequestManagerProxy::watchdogTimerFired): Clear m_pendingDeviceChangeEvent.
(WebKit::UserMediaPermissionRequestManagerProxy::processPregrantedRequests): Deleted.
* UIProcess/UserMediaPermissionRequestManagerProxy.h:

* UIProcess/UserMediaProcessManager.cpp:
(WebKit::UserMediaProcessManager::UserMediaProcessManager): Initialize timer.
(WebKit::UserMediaProcessManager::captureDevicesChanged): New, notify each manager.
(WebKit::UserMediaProcessManager::beginMonitoringCaptureDevices): Cache the device list and
register device change listener the first time it is called.
* UIProcess/UserMediaProcessManager.h:

* UIProcess/WebPageProxy.cpp:
(WebKit::WebPageProxy::viewIsBecomingVisible):
(WebKit::WebPageProxy::beginMonitoringCaptureDevices):
* UIProcess/WebPageProxy.h:
* UIProcess/WebPageProxy.messages.in:

* WebProcess/MediaStream/UserMediaPermissionRequestManager.cpp:
(WebKit::UserMediaPermissionRequestManager::addDeviceChangeObserver): Add listener, tell page
to start monitoring device changes.
(WebKit::UserMediaPermissionRequestManager::removeDeviceChangeObserver): Remove listener.
(WebKit::UserMediaPermissionRequestManager::captureDevicesChanged): Call listeners.
* WebProcess/MediaStream/UserMediaPermissionRequestManager.h:

* WebProcess/WebCoreSupport/WebUserMediaClient.cpp:
(WebKit::WebUserMediaClient::addDeviceChangeObserver):
(WebKit::WebUserMediaClient::removeDeviceChangeObserver):
* WebProcess/WebCoreSupport/WebUserMediaClient.h:

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

* WebProcess/WebProcess.cpp:
(WebKit::WebProcess::addMockMediaDevice):
(WebKit::WebProcess::clearMockMediaDevices):
(WebKit::WebProcess::removeMockMediaDevice):
(WebKit::WebProcess::resetMockMediaDevices):
(WebKit::WebProcess::captureDevicesChanged):
* WebProcess/WebProcess.h:

LayoutTests:

* fast/mediastream/device-change-event-2-expected.txt: Updated.
* fast/mediastream/device-change-event-2.html: Updated.

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

40 files changed:
LayoutTests/ChangeLog
LayoutTests/fast/mediastream/device-change-event-2-expected.txt
LayoutTests/fast/mediastream/device-change-event-2.html
Source/WebCore/ChangeLog
Source/WebCore/Modules/mediastream/MediaDevices.cpp
Source/WebCore/Modules/mediastream/MediaDevices.h
Source/WebCore/Modules/mediastream/UserMediaClient.h
Source/WebCore/Modules/mediastream/UserMediaController.h
Source/WebCore/page/Page.h
Source/WebCore/platform/mediastream/CaptureDeviceManager.cpp
Source/WebCore/platform/mediastream/CaptureDeviceManager.h
Source/WebCore/platform/mediastream/RealtimeMediaSource.cpp
Source/WebCore/platform/mediastream/RealtimeMediaSourceCenter.cpp
Source/WebCore/platform/mediastream/RealtimeMediaSourceCenter.h
Source/WebCore/platform/mediastream/ios/AVAudioSessionCaptureDeviceManager.mm
Source/WebCore/platform/mediastream/mac/AVCaptureDeviceManager.mm
Source/WebCore/platform/mediastream/mac/CoreAudioCaptureDeviceManager.cpp
Source/WebCore/platform/mediastream/mac/CoreAudioCaptureDeviceManager.h
Source/WebCore/platform/mock/MockRealtimeMediaSource.cpp
Source/WebCore/platform/mock/MockRealtimeMediaSourceCenter.cpp
Source/WebCore/testing/Internals.cpp
Source/WebCore/testing/Internals.h
Source/WebCore/testing/Internals.idl
Source/WebKit/ChangeLog
Source/WebKit/Scripts/webkit/messages.py
Source/WebKit/UIProcess/UserMediaPermissionRequestManagerProxy.cpp
Source/WebKit/UIProcess/UserMediaPermissionRequestManagerProxy.h
Source/WebKit/UIProcess/UserMediaProcessManager.cpp
Source/WebKit/UIProcess/UserMediaProcessManager.h
Source/WebKit/UIProcess/WebPageProxy.cpp
Source/WebKit/UIProcess/WebPageProxy.h
Source/WebKit/UIProcess/WebPageProxy.messages.in
Source/WebKit/WebKit.xcodeproj/project.pbxproj
Source/WebKit/WebProcess/MediaStream/UserMediaPermissionRequestManager.cpp
Source/WebKit/WebProcess/MediaStream/UserMediaPermissionRequestManager.h
Source/WebKit/WebProcess/WebCoreSupport/WebUserMediaClient.cpp
Source/WebKit/WebProcess/WebCoreSupport/WebUserMediaClient.h
Source/WebKit/WebProcess/WebPage/WebPage.cpp
Source/WebKit/WebProcess/WebPage/WebPage.h
Source/WebKit/WebProcess/WebPage/WebPage.messages.in

index 9d62327..98fc6f0 100644 (file)
@@ -1,3 +1,14 @@
+2018-08-20  Eric Carlson  <eric.carlson@apple.com>
+
+        [MediaStream] Move capture device monitoring to WebKit
+        https://bugs.webkit.org/show_bug.cgi?id=188521
+        <rdar://problem/43251787>
+
+        Reviewed by Youenn Fablet.
+
+        * fast/mediastream/device-change-event-2-expected.txt: Updated.
+        * fast/mediastream/device-change-event-2.html: Updated.
+
 2018-08-20  Rob Buis  <rbuis@igalia.com>
 
         Throw an exception if window.open() gets passed a URL that cannot be parsed
index 64c6b61..8dcf526 100644 (file)
@@ -1,3 +1,6 @@
 
 PASS 'devicechange' event fired when device list changes 
+PASS 'devicechange' events fired quickly are coalesced 
+PASS 'devicechange' event is not fired when the document doesn't has focus or permission to capture 
+PASS 'devicechange' event is fired when the document doesn't has focus but has permission to capture 
 
index 43d5f2b..614b8d1 100644 (file)
@@ -6,16 +6,25 @@
     <script src="../../resources/testharness.js"></script>
     <script src="../../resources/testharnessreport.js"></script>
     <script>
-    let deviceIds = [];
-    promise_test(async (test) => {
+    let stream = null;
+    
+    let setup = async (test) => {
         if (!window.testRunner)
             return Promise.reject("test requires internal API");
 
         test.add_cleanup(() => { testRunner.resetMockMediaDevices(); });
 
         testRunner.setUserMediaPermission(true);
+        
+        stream = null;
+    }
+
+    promise_test(async (test) => {
+    
+        await setup(test);
 
-        await navigator.mediaDevices.getUserMedia({ audio:true, video:true });
+        await navigator.mediaDevices.getUserMedia({ audio:true, video:true })
+            .then(s => stream = s)
 
         let devices = await navigator.mediaDevices.enumerateDevices();
 
@@ -29,7 +38,7 @@
         await new Promise((resolve, reject) => {
             navigator.mediaDevices.ondevicechange = resolve;
             setTimeout(() => {
-                console.log("event 1 taking a long time");
+                console.log("event 1 took too long");
                 resolve();
             }, 5000);
             testRunner.addMockCameraDevice("id1", "my camera");
@@ -41,7 +50,7 @@
         await new Promise((resolve, reject) => {
             navigator.mediaDevices.ondevicechange = resolve;
             setTimeout(() => {
-                console.log("event 2 taking a long time");
+                console.log("event 2 took too long");
                 resolve();
             }, 5000);
             testRunner.addMockMicrophoneDevice("id2", "my mic");
         assert_equals(devices[0].label, "my mic");
 
     }, "'devicechange' event fired when device list changes");
+
+    promise_test(async (test) => {
+
+        await setup(test);
+
+        let eventCount = 0;
+        await new Promise((resolve, reject) => {
+            navigator.mediaDevices.ondevicechange = (evt) => {
+                ++eventCount;
+                setTimeout(() => {
+                    resolve();
+                }, 500);
+            }
+
+            setTimeout(() => {
+                console.log("navigator.mediaDevices.ondevicechange took too long");
+                resolve();
+            }, 4000);
+
+            testRunner.addMockMicrophoneDevice("id4", "microphone 3");
+            testRunner.addMockMicrophoneDevice("id5", "microphone 4");
+        });
+        assert_equals(eventCount, 1, "one event fired");
+
+    }, "'devicechange' events fired quickly are coalesced");
+
+
+    promise_test(async (test) => {
+
+        await setup(test);
+
+        await new Promise((resolve, reject) => {
+            let timeout = setTimeout(() => {
+                console.log("window.onblur took too long");
+                resolve();
+            }, 5000);
+
+            window.onblur = () => {
+                clearTimeout(timeout);
+                resolve();
+            }
+        
+            internals.setPageIsFocusedAndActive(false);
+        });
+
+        await new Promise((resolve, reject) => {
+            assert_false(document.hasFocus(), "document.hasFocus()");
+
+            navigator.mediaDevices.ondevicechange = () => {
+                assert_true(document.hasFocus(), "devicechange should only fire when the document is focused and active");
+                resolve();
+            };
+
+            setTimeout(() => {
+                internals.setPageIsFocusedAndActive(true);
+            }, 200);
+
+            testRunner.addMockMicrophoneDevice("id3", "microphone 2");
+        });
+
+    }, "'devicechange' event is not fired when the document doesn't has focus or permission to capture");
+
+    promise_test(async (test) => {
+
+        await setup(test);
+
+        await navigator.mediaDevices.getUserMedia({ audio:true, video:true })
+            .then(s => stream = s);
+
+        await new Promise((resolve, reject) => {
+            let timeout = setTimeout(() => {
+                console.log("window.onblur took too long");
+                resolve();
+            }, 5000);
+
+            window.onblur = () => {
+                clearTimeout(timeout);
+                resolve();
+            }
+        
+            internals.setPageIsFocusedAndActive(false);
+        });
+
+        await new Promise((resolve, reject) => {
+            assert_false(document.hasFocus(), "document.hasFocus()");
+
+            navigator.mediaDevices.ondevicechange = () => {
+                assert_false(document.hasFocus(), "devicechange should fire when the document is not focused but can capture");
+                resolve();
+            };
+
+            testRunner.addMockMicrophoneDevice("id3", "microphone 2");
+        });
+
+    }, "'devicechange' event is fired when the document doesn't has focus but has permission to capture");
+
     </script>
 </head>
 <body>
index 70bd1a9..90e7cf0 100644 (file)
@@ -1,3 +1,67 @@
+2018-08-20  Eric Carlson  <eric.carlson@apple.com>
+
+        [MediaStream] Move capture device monitoring to WebKit
+        https://bugs.webkit.org/show_bug.cgi?id=188521
+        <rdar://problem/43251787>
+
+        Reviewed by Youenn Fablet.
+
+        No new tests, updated fast/mediastream/device-change-event-2.html for the changes.
+
+        * Modules/mediastream/MediaDevices.cpp:
+        (WebCore::MediaDevices::MediaDevices): Device change listener is added in addEventListener.
+        (WebCore::MediaDevices::stop): Device change listener is on the user media controller.
+        (WebCore::MediaDevices::addEventListener): Add the device change listener only once the first
+        event handler is added.
+        * Modules/mediastream/MediaDevices.h:
+
+        * Modules/mediastream/UserMediaClient.h:
+        * Modules/mediastream/UserMediaController.h:
+        (WebCore::UserMediaController::addDeviceChangeObserver): Pass through to the client.
+        (WebCore::UserMediaController::removeDeviceChangeObserver): Ditto.
+
+        * platform/mediastream/CaptureDeviceManager.cpp:
+        (CaptureDeviceManager::deviceChanged): Notify RealtimeMediaSourceCenter.
+        (nextObserverToken): Deleted.
+        (CaptureDeviceManager::addCaptureDeviceChangedObserver): Deleted.
+        (CaptureDeviceManager::removeCaptureDeviceChangedObserver): Deleted.
+        * platform/mediastream/CaptureDeviceManager.h:
+
+        * platform/mediastream/RealtimeMediaSourceCenter.cpp:
+        (WebCore::RealtimeMediaSourceCenter::setDevicesChangedObserver):
+        (WebCore::RealtimeMediaSourceCenter::captureDevicesChanged):
+        (WebCore::observerMap): Deleted.
+        (WebCore::RealtimeMediaSourceCenter::addDevicesChangedObserver): Deleted.
+        (WebCore::RealtimeMediaSourceCenter::removeDevicesChangedObserver): Deleted.
+        * platform/mediastream/RealtimeMediaSourceCenter.h:
+
+        * platform/mediastream/ios/AVAudioSessionCaptureDeviceManager.mm:
+        (WebCore::AVAudioSessionCaptureDeviceManager::refreshAudioCaptureDevices): Call base class.
+
+        * platform/mediastream/mac/AVCaptureDeviceManager.mm:
+        (WebCore::AVCaptureDeviceManager::deviceConnected): Ditto.
+        (WebCore::AVCaptureDeviceManager::deviceDisconnected): Ditto.
+
+        * platform/mediastream/mac/CoreAudioCaptureDeviceManager.cpp:
+        (WebCore::deviceHasInputStreams): Drive-by fix, check the number of buffers to see if the
+        device has input streams.
+        (WebCore::CoreAudioCaptureDeviceManager::coreAudioCaptureDevices): Use new bool parameter
+        added to refreshAudioCaptureDevices so we won't trigger a device change event on the first scan.
+        (WebCore::CoreAudioCaptureDeviceManager::refreshAudioCaptureDevices): Add param.
+        (WebCore::CoreAudioCaptureDeviceManager::devicesChanged): Use new param.
+        * platform/mediastream/mac/CoreAudioCaptureDeviceManager.h:
+
+        * platform/mock/MockRealtimeMediaSourceCenter.cpp:
+        (WebCore::MockRealtimeMediaSourceCenter::setDevices): Don't need to call captureDevicesChanged,
+        it is done in the UI process.
+        (WebCore::MockRealtimeMediaSourceCenter::addDevice): Ditto.
+        (WebCore::MockRealtimeMediaSourceCenter::removeDevice): Ditto.
+
+        * testing/InternalSettings.cpp:
+        (WebCore::InternalSettings::setPageIsFocusedAndActive): New, used by updated test.
+        * testing/Internals.h:
+        * testing/Internals.idl:
+
 2018-08-20  Rob Buis  <rbuis@igalia.com>
 
         Throw an exception if window.open() gets passed a URL that cannot be parsed
index 1b18f84..5c0f538 100644 (file)
@@ -1,6 +1,6 @@
 /*
  * Copyright (C) 2015 Ericsson AB. All rights reserved.
- * Copyright (C) 2015-2017 Apple Inc. All rights reserved.
+ * Copyright (C) 2015-2018 Apple Inc. All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions
@@ -41,6 +41,7 @@
 #include "MediaTrackSupportedConstraints.h"
 #include "RealtimeMediaSourceSettings.h"
 #include "RuntimeEnabledFeatures.h"
+#include "UserMediaController.h"
 #include "UserMediaRequest.h"
 #include <wtf/RandomNumber.h>
 
@@ -51,17 +52,6 @@ inline MediaDevices::MediaDevices(Document& document)
     , m_scheduledEventTimer(*this, &MediaDevices::scheduledEventTimerFired)
     , m_eventNames(eventNames())
 {
-    m_deviceChangedToken = RealtimeMediaSourceCenter::singleton().addDevicesChangedObserver([weakThis = makeWeakPtr(*this), this]() {
-
-        if (!weakThis)
-            return;
-
-        // FIXME: We should only dispatch an event if the user has been granted access to the type of
-        // device that was added or removed.
-        if (!m_scheduledEventTimer.isActive())
-            m_scheduledEventTimer.startOneShot(Seconds(randomNumber() / 2));
-    });
-
     suspendIfNeeded();
 
     static_assert(static_cast<size_t>(MediaDevices::DisplayCaptureSurfaceType::Monitor) == static_cast<size_t>(RealtimeMediaSourceSettings::DisplaySurfaceType::Monitor), "MediaDevices::DisplayCaptureSurfaceType::Monitor is not equal to RealtimeMediaSourceSettings::DisplaySurfaceType::Monitor as expected");
@@ -74,8 +64,12 @@ MediaDevices::~MediaDevices() = default;
 
 void MediaDevices::stop()
 {
-    if (m_deviceChangedToken)
-        RealtimeMediaSourceCenter::singleton().removeDevicesChangedObserver(m_deviceChangedToken);
+    if (m_deviceChangeToken) {
+        auto* document = this->document();
+        auto* controller = document ? UserMediaController::from(document->page()) : nullptr;
+        if (document && controller)
+            controller->removeDeviceChangeObserver(m_deviceChangeToken);
+    }
 }
 
 Ref<MediaDevices> MediaDevices::create(Document& document)
@@ -181,6 +175,27 @@ bool MediaDevices::canSuspendForDocumentSuspension() const
     return true;
 }
 
+bool MediaDevices::addEventListener(const AtomicString& eventType, Ref<EventListener>&& listener, const AddEventListenerOptions& options)
+{
+    if (!m_listeningForDeviceChanges && eventType == eventNames().devicechangeEvent) {
+        auto* document = this->document();
+        auto* controller = document ? UserMediaController::from(document->page()) : nullptr;
+        if (document && controller) {
+            m_listeningForDeviceChanges = true;
+
+            m_deviceChangeToken = controller->addDeviceChangeObserver([weakThis = makeWeakPtr(*this), this]() {
+
+                if (!weakThis || m_scheduledEventTimer.isActive())
+                    return;
+
+                m_scheduledEventTimer.startOneShot(Seconds(randomNumber() / 2));
+            });
+        }
+    }
+
+    return EventTargetWithInlineData::addEventListener(eventType, WTFMove(listener), options);
+}
+
 } // namespace WebCore
 
 #endif // ENABLE(MEDIA_STREAM)
index 02d1aef..072ba15 100644 (file)
@@ -1,6 +1,6 @@
 /*
  * Copyright (C) 2015 Ericsson AB. All rights reserved.
- * Copyright (C) 2016 Apple Inc. All rights reserved.
+ * Copyright (C) 2016-2018 Apple Inc. All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions
 #include "MediaTrackConstraints.h"
 #include "RealtimeMediaSourceCenter.h"
 #include "Timer.h"
+#include "UserMediaClient.h"
 #include <wtf/WeakPtr.h>
 
 namespace WebCore {
 
-class Document;
 class MediaDeviceInfo;
 class MediaStream;
 
@@ -85,6 +85,7 @@ private:
     explicit MediaDevices(Document&);
 
     void scheduledEventTimerFired();
+    bool addEventListener(const AtomicString& eventType, Ref<EventListener>&&, const AddEventListenerOptions&) override;
 
     friend class JSMediaDevicesOwner;
 
@@ -101,8 +102,9 @@ private:
     void derefEventTarget() final { deref(); }
 
     Timer m_scheduledEventTimer;
-    RealtimeMediaSourceCenter::DevicesChangedObserverToken m_deviceChangedToken;
+    UserMediaClient::DeviceChangeObserverToken m_deviceChangeToken;
     const EventNames& m_eventNames; // Need to cache this so we can use it from GC threads.
+    bool m_listeningForDeviceChanges { false };
 };
 
 } // namespace WebCore
index 3e3ade1..b2aa560 100644 (file)
@@ -1,6 +1,6 @@
 /*
  * Copyright (C) 2011 Ericsson AB. All rights reserved.
- * Copyright (C) 2016 Apple Inc. All rights reserved.
+ * Copyright (C) 2016-2018 Apple Inc. All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions
@@ -33,6 +33,8 @@
 
 #if ENABLE(MEDIA_STREAM)
 
+#include <wtf/ObjectIdentifier.h>
+
 namespace WebCore {
 
 class MediaDevicesEnumerationRequest;
@@ -49,6 +51,11 @@ public:
     virtual void enumerateMediaDevices(MediaDevicesEnumerationRequest&) = 0;
     virtual void cancelMediaDevicesEnumerationRequest(MediaDevicesEnumerationRequest&) = 0;
 
+    enum DeviceChangeObserverTokenType { };
+    using DeviceChangeObserverToken = ObjectIdentifier<DeviceChangeObserverTokenType>;
+    virtual DeviceChangeObserverToken addDeviceChangeObserver(WTF::Function<void()>&&) = 0;
+    virtual void removeDeviceChangeObserver(DeviceChangeObserverToken) = 0;
+
 protected:
     virtual ~UserMediaClient() = default;
 };
index 2249abf..cfac599 100644 (file)
@@ -1,6 +1,6 @@
 /*
  * Copyright (C) 2012 Google Inc. All rights reserved.
- * Copyright (C) 2016 Apple Inc. All rights reserved.
+ * Copyright (C) 2016-2018 Apple Inc. All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions
@@ -48,6 +48,9 @@ public:
     void enumerateMediaDevices(MediaDevicesEnumerationRequest&);
     void cancelMediaDevicesEnumerationRequest(MediaDevicesEnumerationRequest&);
 
+    UserMediaClient::DeviceChangeObserverToken addDeviceChangeObserver(WTF::Function<void()>&&);
+    void removeDeviceChangeObserver(UserMediaClient::DeviceChangeObserverToken);
+
     WEBCORE_EXPORT static const char* supplementName();
     static UserMediaController* from(Page* page) { return static_cast<UserMediaController*>(Supplement<Page>::from(page, supplementName())); }
 
@@ -75,6 +78,16 @@ inline void UserMediaController::cancelMediaDevicesEnumerationRequest(MediaDevic
     m_client->cancelMediaDevicesEnumerationRequest(request);
 }
 
+inline UserMediaClient::DeviceChangeObserverToken UserMediaController::addDeviceChangeObserver(WTF::Function<void()>&& observer)
+{
+    return m_client->addDeviceChangeObserver(WTFMove(observer));
+}
+
+inline void UserMediaController::removeDeviceChangeObserver(UserMediaClient::DeviceChangeObserverToken token)
+{
+    m_client->removeDeviceChangeObserver(token);
+}
+
 } // namespace WebCore
 
 #endif // ENABLE(MEDIA_STREAM)
index d0d9511..8f7b127 100644 (file)
@@ -434,8 +434,8 @@ public:
     void setIsRestoringCachedPage(bool value) { m_isRestoringCachedPage = value; }
     bool isRestoringCachedPage() const { return m_isRestoringCachedPage; }
 
-    void addActivityStateChangeObserver(ActivityStateChangeObserver&);
-    void removeActivityStateChangeObserver(ActivityStateChangeObserver&);
+    WEBCORE_EXPORT void addActivityStateChangeObserver(ActivityStateChangeObserver&);
+    WEBCORE_EXPORT void removeActivityStateChangeObserver(ActivityStateChangeObserver&);
 
     WEBCORE_EXPORT void suspendScriptedAnimations();
     WEBCORE_EXPORT void resumeScriptedAnimations();
index cd147a0..8a39b29 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2015-2016 Apple Inc. All rights reserved.
+ * Copyright (C) 2015-2018 Apple Inc. All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions
@@ -50,24 +50,14 @@ CaptureDevice CaptureDeviceManager::captureDeviceFromPersistentID(const String&
     return { };
 }
 
-static CaptureDeviceManager::ObserverToken nextObserverToken()
+void CaptureDeviceManager::deviceChanged()
 {
-    static CaptureDeviceManager::ObserverToken nextToken = 0;
-    return ++nextToken;
-}
-
-CaptureDeviceManager::ObserverToken CaptureDeviceManager::addCaptureDeviceChangedObserver(CaptureDeviceChangedCallback&& observer)
-{
-    auto token = nextObserverToken();
-    m_observers.set(token, WTFMove(observer));
-    return token;
-}
+    callOnMainThread([weakThis = makeWeakPtr(*this)] {
+        if (!weakThis)
+            return;
 
-void CaptureDeviceManager::removeCaptureDeviceChangedObserver(ObserverToken token)
-{
-    ASSERT(m_observers.contains(token));
-    m_observers.remove(token);
+        RealtimeMediaSourceCenter::singleton().captureDevicesChanged();
+    });
 }
 
-
 #endif // ENABLE(MEDIA_STREAM)
index 45edb30..5732de0 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2015-2016 Apple Inc. All rights reserved.
+ * Copyright (C) 2015-2018 Apple Inc. All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions
 
 #include "CaptureDevice.h"
 #include "RealtimeMediaSource.h"
+#include <wtf/WeakPtr.h>
 
 namespace WebCore {
 
-class CaptureDeviceManager {
+class CaptureDeviceManager : public CanMakeWeakPtr<CaptureDeviceManager> {
 public:
-    using CaptureDeviceChangedCallback = WTF::Function<void()>;
-    using ObserverToken = uint32_t;
-    virtual ObserverToken addCaptureDeviceChangedObserver(CaptureDeviceChangedCallback&&);
-    virtual void removeCaptureDeviceChangedObserver(ObserverToken);
-
     virtual const Vector<CaptureDevice>& captureDevices() = 0;
     virtual std::optional<CaptureDevice> captureDeviceWithPersistentID(CaptureDevice::DeviceType, const String&) { return std::nullopt; }
 
 protected:
     virtual ~CaptureDeviceManager();
     CaptureDevice captureDeviceFromPersistentID(const String& captureDeviceID);
-    HashMap<ObserverToken, CaptureDeviceChangedCallback> m_observers;
+    void deviceChanged();
 };
 
 } // namespace WebCore
index 952119c..8a4609a 100644 (file)
@@ -246,10 +246,8 @@ bool RealtimeMediaSource::supportsSizeAndFrameRate(std::optional<IntConstraint>
         }
 
         distance = std::min(distance, constraintDistance);
-        if (widthConstraint->isMandatory()) {
-            auto range = capabilities.width();
-            width = widthConstraint->valueForCapabilityRange(size().width(), range.rangeMin().asInt, range.rangeMax().asInt);
-        }
+        auto range = capabilities.width();
+        width = widthConstraint->valueForCapabilityRange(size().width(), range.rangeMin().asInt, range.rangeMax().asInt);
     }
 
     std::optional<int> height;
@@ -261,10 +259,8 @@ bool RealtimeMediaSource::supportsSizeAndFrameRate(std::optional<IntConstraint>
         }
 
         distance = std::min(distance, constraintDistance);
-        if (heightConstraint->isMandatory()) {
-            auto range = capabilities.height();
-            height = heightConstraint->valueForCapabilityRange(size().height(), range.rangeMin().asInt, range.rangeMax().asInt);
-        }
+        auto range = capabilities.height();
+        height = heightConstraint->valueForCapabilityRange(size().height(), range.rangeMin().asInt, range.rangeMax().asInt);
     }
 
     std::optional<double> frameRate;
@@ -276,10 +272,8 @@ bool RealtimeMediaSource::supportsSizeAndFrameRate(std::optional<IntConstraint>
         }
 
         distance = std::min(distance, constraintDistance);
-        if (frameRateConstraint->isMandatory()) {
-            auto range = capabilities.frameRate();
-            frameRate = frameRateConstraint->valueForCapabilityRange(this->frameRate(), range.rangeMin().asDouble, range.rangeMax().asDouble);
-        }
+        auto range = capabilities.frameRate();
+        frameRate = frameRateConstraint->valueForCapabilityRange(this->frameRate(), range.rangeMin().asDouble, range.rangeMax().asDouble);
     }
 
     // Each of the non-null values is supported individually, see if they all can be applied at the same time.
index 3886ff8..ffd51d4 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * Copyright (C) 2011 Ericsson AB. All rights reserved.
  * Copyright (C) 2012 Google Inc. All rights reserved.
- * Copyright (C) 2013-2016 Apple Inc. All rights reserved.
+ * Copyright (C) 2013-2018 Apple Inc. All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions
@@ -53,12 +53,6 @@ static RealtimeMediaSourceCenter*& mediaStreamCenterOverride()
     return override;
 }
 
-static HashMap<unsigned, std::function<void()>>& observerMap()
-{
-    static NeverDestroyed<HashMap<unsigned, std::function<void()>>> map;
-    return map;
-}
-
 RealtimeMediaSourceCenter& RealtimeMediaSourceCenter::singleton()
 {
     RealtimeMediaSourceCenter* override = mediaStreamCenterOverride();
@@ -199,25 +193,18 @@ ExceptionOr<void> RealtimeMediaSourceCenter::setDeviceEnabled(const String& id,
     return Exception { NotFoundError };
 }
 
-RealtimeMediaSourceCenter::DevicesChangedObserverToken RealtimeMediaSourceCenter::addDevicesChangedObserver(std::function<void()>&& observer)
-{
-    static DevicesChangedObserverToken nextToken = 0;
-    observerMap().set(++nextToken, WTFMove(observer));
-    return nextToken;
-}
-
-void RealtimeMediaSourceCenter::removeDevicesChangedObserver(DevicesChangedObserverToken token)
+void RealtimeMediaSourceCenter::setDevicesChangedObserver(std::function<void()>&& observer)
 {
-    bool wasRemoved = observerMap().remove(token);
-    ASSERT_UNUSED(wasRemoved, wasRemoved);
+    ASSERT(isMainThread());
+    ASSERT(!m_deviceChangedObserver);
+    m_deviceChangedObserver = WTFMove(observer);
 }
 
 void RealtimeMediaSourceCenter::captureDevicesChanged()
 {
-    // Copy the hash map because the observer callback may call back in and modify the map.
-    auto callbacks = observerMap();
-    for (auto& it : callbacks)
-        it.value();
+    ASSERT(isMainThread());
+    if (m_deviceChangedObserver)
+        m_deviceChangedObserver();
 }
 
 void RealtimeMediaSourceCenter::validateRequestConstraints(ValidConstraintsHandler&& validHandler, InvalidConstraintsHandler&& invalidHandler, const MediaStreamRequest& request, String&& deviceIdentifierHashSalt)
index ef7b3cf..d54ae8e 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * Copyright (C) 2011 Ericsson AB. All rights reserved.
  * Copyright (C) 2012 Google Inc. All rights reserved.
- * Copyright (C) 2013-2017 Apple Inc. All rights reserved.
+ * Copyright (C) 2013-2018 Apple Inc. All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions
@@ -85,22 +85,22 @@ public:
     WEBCORE_EXPORT CaptureDevice captureDeviceWithUniqueID(const String& id, const String& hashSalt);
     WEBCORE_EXPORT ExceptionOr<void> setDeviceEnabled(const String&, bool);
 
-    using DevicesChangedObserverToken = unsigned;
-    DevicesChangedObserverToken addDevicesChangedObserver(std::function<void()>&&);
-    void removeDevicesChangedObserver(DevicesChangedObserverToken);
+    WEBCORE_EXPORT void setDevicesChangedObserver(std::function<void()>&&);
 
     void setVideoCapturePageState(bool, bool);
 
+    void captureDevicesChanged();
+
 protected:
     RealtimeMediaSourceCenter();
 
-    void captureDevicesChanged();
-
     static RealtimeMediaSourceCenter& platformCenter();
     RealtimeMediaSourceSupportedConstraints m_supportedConstraints;
 
     CaptureDeviceManager* m_audioCaptureDeviceManager { nullptr };
     CaptureDeviceManager* m_videoCaptureDeviceManager { nullptr };
+
+    WTF::Function<void()> m_deviceChangedObserver;
 };
 
 } // namespace WebCore
index 32e70e1..f61d8df 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2017 Apple Inc. All rights reserved.
+ * Copyright (C) 2017-2018 Apple Inc. All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions
@@ -29,6 +29,7 @@
 #if ENABLE(MEDIA_STREAM) && PLATFORM(IOS)
 
 #include "AVAudioSessionCaptureDevice.h"
+#include "RealtimeMediaSourceCenter.h"
 #include <AVFoundation/AVAudioSession.h>
 #include <wtf/SoftLinking.h>
 #include <wtf/Vector.h>
@@ -141,8 +142,7 @@ void AVAudioSessionCaptureDeviceManager::refreshAudioCaptureDevices()
     m_audioSessionCaptureDevices = WTFMove(newAudioDevices);
     m_devices = WTFMove(newDevices);
 
-    for (auto& observer : m_observers.values())
-        observer();
+    deviceChanged();
 }
 
 } // namespace WebCore
index c011b26..0efc92a 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2013-2015 Apple Inc. All rights reserved.
+ * Copyright (C) 2013-2018 Apple Inc. All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions
@@ -179,9 +179,7 @@ void AVCaptureDeviceManager::registerForDeviceNotifications()
 void AVCaptureDeviceManager::deviceConnected()
 {
     refreshCaptureDevices();
-
-    for (auto& observer : m_observers.values())
-        observer();
+    deviceChanged();
 }
 
 void AVCaptureDeviceManager::deviceDisconnected(AVCaptureDeviceTypedef* device)
@@ -200,8 +198,7 @@ void AVCaptureDeviceManager::deviceDisconnected(AVCaptureDeviceTypedef* device)
         }
     }
 
-    for (auto& observer : m_observers.values())
-        observer();
+    deviceChanged();
 }
 
 } // namespace WebCore
index 5413a8f..1111eab 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2017 Apple Inc. All rights reserved.
+ * Copyright (C) 2017-2018 Apple Inc. All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions
@@ -30,6 +30,7 @@
 
 #include "CoreAudioCaptureDevice.h"
 #include "Logging.h"
+#include "RealtimeMediaSourceCenter.h"
 #include <AudioUnit/AudioUnit.h>
 #include <CoreMedia/CMSync.h>
 #include <wtf/Assertions.h>
@@ -64,10 +65,17 @@ std::optional<CaptureDevice> CoreAudioCaptureDeviceManager::captureDeviceWithPer
 static bool deviceHasInputStreams(AudioObjectID deviceID)
 {
     UInt32 dataSize = 0;
-    AudioObjectPropertyAddress address = { kAudioDevicePropertyStreams, kAudioDevicePropertyScopeInput, kAudioObjectPropertyElementMaster };
+    AudioObjectPropertyAddress address = { kAudioDevicePropertyStreamConfiguration, kAudioDevicePropertyScopeInput, kAudioObjectPropertyElementMaster };
     auto err = AudioObjectGetPropertyDataSize(deviceID, &address, 0, nullptr, &dataSize);
 
-    return !err && dataSize;
+    if (err || !dataSize)
+        return false;
+
+    auto bufferList = std::unique_ptr<AudioBufferList>((AudioBufferList*) ::operator new (dataSize));
+    memset(bufferList.get(), 0, dataSize);
+    err = AudioObjectGetPropertyData(deviceID, &address, 0, nullptr, &dataSize, bufferList.get());
+
+    return !err && bufferList->mNumberBuffers;
 }
 
 static bool isValidCaptureDevice(const CoreAudioCaptureDevice& device)
@@ -81,7 +89,7 @@ Vector<CoreAudioCaptureDevice>& CoreAudioCaptureDeviceManager::coreAudioCaptureD
     static bool initialized;
     if (!initialized) {
         initialized = true;
-        refreshAudioCaptureDevices();
+        refreshAudioCaptureDevices(DoNotNotify);
 
         AudioObjectPropertyAddress address = { kAudioHardwarePropertyDevices, kAudioObjectPropertyScopeGlobal, kAudioObjectPropertyElementMaster };
         auto err = AudioObjectAddPropertyListener(kAudioObjectSystemObject, &address, devicesChanged, this);
@@ -102,7 +110,7 @@ std::optional<CoreAudioCaptureDevice> CoreAudioCaptureDeviceManager::coreAudioDe
 }
 
 
-void CoreAudioCaptureDeviceManager::refreshAudioCaptureDevices()
+void CoreAudioCaptureDeviceManager::refreshAudioCaptureDevices(NotifyIfDevicesHaveChanged notify)
 {
     AudioObjectPropertyAddress address = { kAudioHardwarePropertyDevices, kAudioObjectPropertyScopeGlobal, kAudioObjectPropertyElementMaster };
     UInt32 dataSize = 0;
@@ -156,13 +164,13 @@ void CoreAudioCaptureDeviceManager::refreshAudioCaptureDevices()
         m_devices.append(captureDevice);
     }
 
-    for (auto& observer : m_observers.values())
-        observer();
+    if (notify == Notify)
+        deviceChanged();
 }
 
 OSStatus CoreAudioCaptureDeviceManager::devicesChanged(AudioObjectID, UInt32, const AudioObjectPropertyAddress*, void* userData)
 {
-    static_cast<CoreAudioCaptureDeviceManager*>(userData)->refreshAudioCaptureDevices();
+    static_cast<CoreAudioCaptureDeviceManager*>(userData)->refreshAudioCaptureDevices(Notify);
     return 0;
 }
 
index 8c28e82..cf48276 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2017 Apple Inc. All rights reserved.
+ * Copyright (C) 2017-2018 Apple Inc. All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions
@@ -55,7 +55,8 @@ private:
     static OSStatus devicesChanged(AudioObjectID, UInt32, const AudioObjectPropertyAddress*, void*);
     Vector<CoreAudioCaptureDevice>& coreAudioCaptureDevices();
 
-    void refreshAudioCaptureDevices();
+    enum NotifyIfDevicesHaveChanged { Notify, DoNotNotify };
+    void refreshAudioCaptureDevices(NotifyIfDevicesHaveChanged);
 
     Vector<CaptureDevice> m_devices;
     Vector<CoreAudioCaptureDevice> m_coreAudioCaptureDevices;
index 0875497..ec441ef 100644 (file)
@@ -97,6 +97,7 @@ void MockRealtimeMediaSource::createCaptureDevice(const MockMediaDevice& device)
 void MockRealtimeMediaSource::resetDevices()
 {
     setDevices(defaultDevices());
+    RealtimeMediaSourceCenter::singleton().captureDevicesChanged();
 }
 
 void MockRealtimeMediaSource::setDevices(Vector<MockMediaDevice>&& newMockDevices)
@@ -115,6 +116,7 @@ void MockRealtimeMediaSource::setDevices(Vector<MockMediaDevice>&& newMockDevice
         map.add(device.persistentId, device);
         createCaptureDevice(device);
     }
+    RealtimeMediaSourceCenter::singleton().captureDevicesChanged();
 }
 
 void MockRealtimeMediaSource::addDevice(const MockMediaDevice& device)
@@ -122,6 +124,7 @@ void MockRealtimeMediaSource::addDevice(const MockMediaDevice& device)
     devices().append(device);
     deviceMap().set(device.persistentId, device);
     createCaptureDevice(device);
+    RealtimeMediaSourceCenter::singleton().captureDevicesChanged();
 }
 
 void MockRealtimeMediaSource::removeDevice(const String& persistentId)
@@ -140,6 +143,7 @@ void MockRealtimeMediaSource::removeDevice(const String& persistentId)
     });
 
     map.remove(iterator);
+    RealtimeMediaSourceCenter::singleton().captureDevicesChanged();
 }
 
 std::optional<CaptureDevice> MockRealtimeMediaSource::captureDeviceWithPersistentID(CaptureDevice::DeviceType type, const String& id)
index df91ebe..db68821 100644 (file)
@@ -1,6 +1,6 @@
 /*
  * Copyright (C) 2013 Google Inc. All rights reserved.
- * Copyright (C) 2013 Apple Inc.  All rights reserved.
+ * Copyright (C) 2013-2018 Apple Inc.  All rights reserved.
  * Copyright (C) 2013 Nokia Corporation and/or its subsidiary(-ies).
  *
  * Redistribution and use in source and binary forms, with or without
@@ -55,19 +55,16 @@ void MockRealtimeMediaSourceCenter::setMockRealtimeMediaSourceCenterEnabled(bool
 void MockRealtimeMediaSourceCenter::setDevices(Vector<MockMediaDevice>&& newMockDevices)
 {
     MockRealtimeMediaSource::setDevices(WTFMove(newMockDevices));
-    singleton().captureDevicesChanged();
 }
 
 void MockRealtimeMediaSourceCenter::addDevice(const MockMediaDevice& device)
 {
     MockRealtimeMediaSource::addDevice(device);
-    singleton().captureDevicesChanged();
 }
 
 void MockRealtimeMediaSourceCenter::removeDevice(const String& persistentId)
 {
     MockRealtimeMediaSource::removeDevice(persistentId);
-    singleton().captureDevicesChanged();
 }
 
 } // namespace WebCore
index 83392bd..0f37961 100644 (file)
@@ -29,6 +29,7 @@
 
 #include "AXObjectCache.h"
 #include "ActiveDOMCallbackMicrotask.h"
+#include "ActivityState.h"
 #include "AnimationTimeline.h"
 #include "ApplicationCacheStorage.h"
 #include "AudioSession.h"
@@ -4345,6 +4346,22 @@ void Internals::setPageVisibility(bool isVisible)
     page.setActivityState(state);
 }
 
+void Internals::setPageIsFocusedAndActive(bool isFocusedAndActive)
+{
+    auto* document = contextDocument();
+    if (!document || !document->page())
+        return;
+    auto& page = *document->page();
+    auto state = page.activityState();
+
+    if (!isFocusedAndActive)
+        state -= { ActivityState::IsFocused, ActivityState::WindowIsActive };
+    else
+        state |= { ActivityState::IsFocused, ActivityState::WindowIsActive };
+
+    page.setActivityState(state);
+}
+
 #if ENABLE(WEB_RTC)
 void Internals::setH264HardwareEncoderAllowed(bool allowed)
 {
index 9c1cab9..8199ea4 100644 (file)
@@ -645,6 +645,8 @@ public:
 #endif
 
     void setPageVisibility(bool isVisible);
+    void setPageIsFocusedAndActive(bool);
+
 
 #if ENABLE(WEB_RTC)
     void setH264HardwareEncoderAllowed(bool allowed);
index 2322663..04f77ac 100644 (file)
@@ -604,6 +604,7 @@ enum CompositingPolicy {
     [Conditional=WEBGL] void failNextGPUStatusCheck(WebGLRenderingContext context);
 
     void setPageVisibility(boolean isVisible);
+    void setPageIsFocusedAndActive(boolean isFocused);
 
     [Conditional=WEB_RTC] void setH264HardwareEncoderAllowed(boolean allowed);
     [Conditional=WEB_RTC] void applyRotationForOutgoingVideoSources(RTCPeerConnection connection);
index 65f4f10..25a94ff 100644 (file)
@@ -1,3 +1,57 @@
+2018-08-20  Eric Carlson  <eric.carlson@apple.com>
+
+        [MediaStream] Move capture device monitoring to WebKit
+        https://bugs.webkit.org/show_bug.cgi?id=188521
+        <rdar://problem/43251787>
+
+        Reviewed by Youenn Fablet.
+
+        * UIProcess/UserMediaPermissionRequestManagerProxy.cpp:
+        (WebKit::UserMediaPermissionRequestManagerProxy::captureDevicesChanged): Notify as appropriate.
+        (WebKit::UserMediaPermissionRequestManagerProxy::viewIsBecomingVisible): Change name from
+        viewIsBecomingVisible. Call captureDevicesChanged if a change happened when not visible.
+        (WebKit::UserMediaPermissionRequestManagerProxy::watchdogTimerFired): Clear m_pendingDeviceChangeEvent.
+        (WebKit::UserMediaPermissionRequestManagerProxy::processPregrantedRequests): Deleted.
+        * UIProcess/UserMediaPermissionRequestManagerProxy.h:
+
+        * UIProcess/UserMediaProcessManager.cpp:
+        (WebKit::UserMediaProcessManager::UserMediaProcessManager): Initialize timer.
+        (WebKit::UserMediaProcessManager::captureDevicesChanged): New, notify each manager.
+        (WebKit::UserMediaProcessManager::beginMonitoringCaptureDevices): Cache the device list and 
+        register device change listener the first time it is called.
+        * UIProcess/UserMediaProcessManager.h:
+
+        * UIProcess/WebPageProxy.cpp:
+        (WebKit::WebPageProxy::viewIsBecomingVisible):
+        (WebKit::WebPageProxy::beginMonitoringCaptureDevices):
+        * UIProcess/WebPageProxy.h:
+        * UIProcess/WebPageProxy.messages.in:
+
+        * WebProcess/MediaStream/UserMediaPermissionRequestManager.cpp:
+        (WebKit::UserMediaPermissionRequestManager::addDeviceChangeObserver): Add listener, tell page
+        to start monitoring device changes.
+        (WebKit::UserMediaPermissionRequestManager::removeDeviceChangeObserver): Remove listener.
+        (WebKit::UserMediaPermissionRequestManager::captureDevicesChanged): Call listeners.
+        * WebProcess/MediaStream/UserMediaPermissionRequestManager.h:
+
+        * WebProcess/WebCoreSupport/WebUserMediaClient.cpp:
+        (WebKit::WebUserMediaClient::addDeviceChangeObserver):
+        (WebKit::WebUserMediaClient::removeDeviceChangeObserver):
+        * WebProcess/WebCoreSupport/WebUserMediaClient.h:
+
+        * WebProcess/WebPage/WebPage.cpp:
+        (WebKit::WebPage::captureDevicesChanged):
+        * WebProcess/WebPage/WebPage.h:
+        * WebProcess/WebPage/WebPage.messages.in:
+
+        * WebProcess/WebProcess.cpp:
+        (WebKit::WebProcess::addMockMediaDevice):
+        (WebKit::WebProcess::clearMockMediaDevices):
+        (WebKit::WebProcess::removeMockMediaDevice):
+        (WebKit::WebProcess::resetMockMediaDevices):
+        (WebKit::WebProcess::captureDevicesChanged):
+        * WebProcess/WebProcess.h:
+
 2018-08-20  Carlos Garcia Campos  <cgarcia@igalia.com>
 
         Unreviewed. Fix GTK/WPE cookie API tests after r234396.
index a782baa..09e464f 100644 (file)
@@ -419,6 +419,7 @@ def headers_for_type(type):
         'WebCore::SelectionRect': ['"EditorState.h"'],
         'WebKit::ActivityStateChangeID': ['"DrawingAreaInfo.h"'],
         'WebKit::BackForwardListItemState': ['"SessionState.h"'],
+        'WebKit::DeviceAccessState': ['"UserMediaPermissionRequestManager.h"'],
         'WebKit::LayerHostingMode': ['"LayerTreeContext.h"'],
         'WebKit::PageState': ['"SessionState.h"'],
         'WebKit::WebGestureEvent': ['"WebEvent.h"'],
index 3c07295..02b2a23 100644 (file)
@@ -1,6 +1,6 @@
 /*
  * Copyright (C) 2014 Igalia S.L.
- * Copyright (C) 2016-2017 Apple Inc. All rights reserved.
+ * Copyright (C) 2016-2018 Apple Inc. All rights reserved.
  *
  *  This library is free software; you can redistribute it and/or
  *  modify it under the terms of the GNU Lesser General Public
@@ -22,6 +22,7 @@
 
 #include "APISecurityOrigin.h"
 #include "APIUIClient.h"
+#include "UserMediaPermissionRequestManager.h"
 #include "UserMediaProcessManager.h"
 #include "WebAutomationSession.h"
 #include "WebPageMessages.h"
@@ -77,6 +78,15 @@ void UserMediaPermissionRequestManagerProxy::stopCapture()
     m_page.stopMediaCapture();
 }
 
+void UserMediaPermissionRequestManagerProxy::captureDevicesChanged()
+{
+#if ENABLE(MEDIA_STREAM)
+    // FIXME: a page with persistent access should always get device change notifications.
+    auto accessState = m_grantedRequests.isEmpty() ? DeviceAccessState::NoAccess : DeviceAccessState::SessionAccess;
+    m_page.process().send(Messages::WebPage::CaptureDevicesChanged(accessState), m_page.pageID());
+#endif
+}
+
 void UserMediaPermissionRequestManagerProxy::clearCachedState()
 {
     invalidatePendingRequests();
@@ -434,7 +444,7 @@ void UserMediaPermissionRequestManagerProxy::captureStateChanged(MediaProducer::
 #endif
 }
 
-void UserMediaPermissionRequestManagerProxy::processPregrantedRequests()
+void UserMediaPermissionRequestManagerProxy::viewIsBecomingVisible()
 {
     for (auto& request : m_pregrantedRequests)
         request->allow();
index 573af04..8d3c096 100644 (file)
@@ -1,6 +1,6 @@
 /*
  * Copyright (C) 2014 Igalia S.L.
- * Copyright (C) 2016 Apple Inc. All rights reserved.
+ * Copyright (C) 2016-2018 Apple Inc. All rights reserved.
  *
  *  This library is free software; you can redistribute it and/or
  *  modify it under the terms of the GNU Lesser General Public
@@ -50,7 +50,7 @@ public:
     void requestUserMediaPermissionForFrame(uint64_t userMediaID, uint64_t frameID, Ref<WebCore::SecurityOrigin>&&  userMediaDocumentOrigin, Ref<WebCore::SecurityOrigin>&& topLevelDocumentOrigin, const WebCore::MediaStreamRequest&);
 
     void resetAccess(uint64_t mainFrameID);
-    void processPregrantedRequests();
+    void viewIsBecomingVisible();
 
     void userMediaAccessWasGranted(uint64_t, WebCore::CaptureDevice&& audioDevice, WebCore::CaptureDevice&& videoDevice);
     void userMediaAccessWasDenied(uint64_t, UserMediaPermissionRequestProxy::UserMediaAccessDenialReason);
@@ -61,6 +61,7 @@ public:
     void scheduleNextRejection();
     void rejectionTimerFired();
     void clearCachedState();
+    void captureDevicesChanged();
 
     void captureStateChanged(WebCore::MediaProducer::MediaStateFlags oldState, WebCore::MediaProducer::MediaStateFlags newState);
 
index 7ae6909..7025d4d 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2016 Apple Inc. All rights reserved.
+ * Copyright (C) 2016-2018 Apple Inc. All rights reserved.
  *
  *  This library is free software; you can redistribute it and/or
  *  modify it under the terms of the GNU Lesser General Public
@@ -25,6 +25,7 @@
 #include "WebPageMessages.h"
 #include "WebPageProxy.h"
 #include "WebProcessProxy.h"
+#include <WebCore/RealtimeMediaSourceCenter.h>
 #include <wtf/HashMap.h>
 #include <wtf/NeverDestroyed.h>
 
@@ -35,6 +36,8 @@ static const ASCIILiteral audioExtensionPath { "com.apple.webkit.microphone"_s }
 static const ASCIILiteral videoExtensionPath { "com.apple.webkit.camera"_s };
 #endif
 
+static const Seconds deviceChangeDebounceTimerInterval { 200_ms };
+
 class ProcessState {
 public:
     ProcessState() { }
@@ -101,6 +104,11 @@ UserMediaProcessManager& UserMediaProcessManager::singleton()
     return manager;
 }
 
+UserMediaProcessManager::UserMediaProcessManager()
+    : m_debounceTimer(RunLoop::main(), this, &UserMediaProcessManager::captureDevicesChanged)
+{
+}
+
 void UserMediaProcessManager::addUserMediaPermissionRequestManagerProxy(UserMediaPermissionRequestManagerProxy& proxy)
 {
     processState(proxy.page().process()).addRequestManager(proxy);
@@ -254,6 +262,58 @@ void UserMediaProcessManager::setCaptureEnabled(bool enabled)
     }
 }
 
+void UserMediaProcessManager::captureDevicesChanged()
+{
+    auto& map = stateMap();
+    for (auto& state : map) {
+        auto* process = state.key;
+        for (auto& manager : state.value->managers()) {
+            if (map.find(process) == map.end())
+                break;
+            manager->captureDevicesChanged();
+        }
+    }
+}
+
+void UserMediaProcessManager::beginMonitoringCaptureDevices()
+{
+    static std::once_flag onceFlag;
+
+    std::call_once(onceFlag, [this] {
+        m_captureDevices = WebCore::RealtimeMediaSourceCenter::singleton().getMediaStreamDevices();
+
+        WebCore::RealtimeMediaSourceCenter::singleton().setDevicesChangedObserver([this]() {
+            auto oldDevices = WTFMove(m_captureDevices);
+            m_captureDevices = WebCore::RealtimeMediaSourceCenter::singleton().getMediaStreamDevices();
+
+            if (m_captureDevices.size() == oldDevices.size()) {
+                bool haveChanges = false;
+                for (auto &newDevice : m_captureDevices) {
+                    if (newDevice.type() != WebCore::CaptureDevice::DeviceType::Camera && newDevice.type() != WebCore::CaptureDevice::DeviceType::Microphone)
+                        continue;
+
+                    auto index = oldDevices.findMatching([&newDevice] (auto& oldDevice) {
+                        return newDevice.persistentId() == oldDevice.persistentId() && newDevice.enabled() != oldDevice.enabled();
+                    });
+
+                    if (index == notFound) {
+                        haveChanges = true;
+                        break;
+                    }
+                }
+
+                if (!haveChanges)
+                    return;
+            }
+
+            // When a device with camera and microphone is attached or detached, the CaptureDevice notification for
+            // the different devices won't arrive at the same time so delay a bit so we can coalesce the callbacks.
+            if (!m_debounceTimer.isActive())
+                m_debounceTimer.startOneShot(deviceChangeDebounceTimerInterval);
+        });
+    });
+}
+
 } // namespace WebKit
 
 #endif
index 81998b4..ae16ebe 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2016 Apple Inc. All rights reserved.
+ * Copyright (C) 2016-2018 Apple Inc. All rights reserved.
  *
  *  This library is free software; you can redistribute it and/or
  *  modify it under the terms of the GNU Lesser General Public
@@ -21,6 +21,8 @@
 #if ENABLE(MEDIA_STREAM)
 
 #include "UserMediaPermissionRequestManagerProxy.h"
+#include <WebCore/CaptureDevice.h>
+#include <wtf/RunLoop.h>
 
 namespace WebKit {
 
@@ -31,6 +33,8 @@ public:
 
     static UserMediaProcessManager& singleton();
 
+    UserMediaProcessManager();
+
     void addUserMediaPermissionRequestManagerProxy(UserMediaPermissionRequestManagerProxy&);
     void removeUserMediaPermissionRequestManagerProxy(UserMediaPermissionRequestManagerProxy&);
 
@@ -45,7 +49,13 @@ public:
 
     void denyNextUserMediaRequest() { m_denyNextRequest = true; }
 
+    void beginMonitoringCaptureDevices();
+
 private:
+    void captureDevicesChanged();
+
+    Vector<WebCore::CaptureDevice> m_captureDevices;
+    RunLoop::Timer<UserMediaProcessManager> m_debounceTimer;
     bool m_captureEnabled { true };
     bool m_denyNextRequest { false };
 };
index 270423f..8acd1b2 100644 (file)
@@ -3842,7 +3842,7 @@ void WebPageProxy::didChangeMainDocument(uint64_t frameID)
 void WebPageProxy::viewIsBecomingVisible()
 {
 #if ENABLE(MEDIA_STREAM)
-    userMediaPermissionRequestManager().processPregrantedRequests();
+    userMediaPermissionRequestManager().viewIsBecomingVisible();
 #endif
 }
 
@@ -6459,6 +6459,13 @@ void WebPageProxy::enumerateMediaDevicesForFrame(uint64_t userMediaID, uint64_t
 #endif
 }
 
+void WebPageProxy::beginMonitoringCaptureDevices()
+{
+#if ENABLE(MEDIA_STREAM)
+    UserMediaProcessManager::singleton().beginMonitoringCaptureDevices();
+#endif
+}
+
 void WebPageProxy::clearUserMediaState()
 {
 #if ENABLE(MEDIA_STREAM)
index a6f9587..9f625dd 100644 (file)
@@ -1487,6 +1487,7 @@ private:
 #endif
     void requestUserMediaPermissionForFrame(uint64_t userMediaID, uint64_t frameID, const WebCore::SecurityOriginData& userMediaDocumentOriginIdentifier, const WebCore::SecurityOriginData& topLevelDocumentOriginIdentifier, const WebCore::MediaStreamRequest&);
     void enumerateMediaDevicesForFrame(uint64_t userMediaID, uint64_t frameID, const WebCore::SecurityOriginData& userMediaDocumentOriginData, const WebCore::SecurityOriginData& topLevelDocumentOriginData);
+    void beginMonitoringCaptureDevices();
 
     void runModal();
     void notifyScrollerThumbIsVisibleInRect(const WebCore::IntRect&);
index 68d6cb9..89cafae 100644 (file)
@@ -287,6 +287,7 @@ messages -> WebPageProxy {
     # MediaSteam messages
     RequestUserMediaPermissionForFrame(uint64_t userMediaID, uint64_t frameID, struct WebCore::SecurityOriginData userMediaDocumentOriginIdentifier, struct WebCore::SecurityOriginData topLevelDocumentOriginIdentifier, struct WebCore::MediaStreamRequest request)
     EnumerateMediaDevicesForFrame(uint64_t userMediaID, uint64_t frameID, struct WebCore::SecurityOriginData userMediaDocumentOriginIdentifier, struct WebCore::SecurityOriginData topLevelDocumentOriginIdentifier)
+    BeginMonitoringCaptureDevices()
 #endif
 
     # Notification messages
index 6bd98ba..b653986 100644 (file)
@@ -85,6 +85,7 @@
                074E75FE1DF2211900D318EC /* UserMediaProcessManager.h in Headers */ = {isa = PBXBuildFile; fileRef = 074E75FB1DF1FD1300D318EC /* UserMediaProcessManager.h */; };
                074E76021DF707BE00D318EC /* MediaDeviceSandboxExtensions.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 074E76001DF7075D00D318EC /* MediaDeviceSandboxExtensions.cpp */; };
                076E884E1A13CADF005E90FC /* APIContextMenuClient.h in Headers */ = {isa = PBXBuildFile; fileRef = 076E884D1A13CADF005E90FC /* APIContextMenuClient.h */; };
+               0772811D21234FF600C8EF2E /* UserMediaPermissionRequestManager.h in Headers */ = {isa = PBXBuildFile; fileRef = 4A410F4319AF7B27002EBAB5 /* UserMediaPermissionRequestManager.h */; };
                07A5EBBB1C7BA43E00B9CA69 /* WKFrameHandleRef.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 07A5EBB91C7BA43E00B9CA69 /* WKFrameHandleRef.cpp */; };
                07A5EBBC1C7BA43E00B9CA69 /* WKFrameHandleRef.h in Headers */ = {isa = PBXBuildFile; fileRef = 07A5EBBA1C7BA43E00B9CA69 /* WKFrameHandleRef.h */; settings = {ATTRIBUTES = (Private, ); }; };
                0E97D74D200E900400BF6643 /* SafeBrowsingSPI.h in Headers */ = {isa = PBXBuildFile; fileRef = 0E97D74C200E8FF300BF6643 /* SafeBrowsingSPI.h */; };
                                CD491B131E73482100009066 /* UserMediaCaptureManagerProxy.h in Headers */,
                                CD491B181E73525500009066 /* UserMediaCaptureManagerProxyMessages.h in Headers */,
                                07297F9F1C17BBEA003F0735 /* UserMediaPermissionCheckProxy.h in Headers */,
+                               0772811D21234FF600C8EF2E /* UserMediaPermissionRequestManager.h in Headers */,
                                4A3CC18B19B0640F00D14AEF /* UserMediaPermissionRequestManagerProxy.h in Headers */,
                                4A3CC18D19B0641900D14AEF /* UserMediaPermissionRequestProxy.h in Headers */,
                                074E75FE1DF2211900D318EC /* UserMediaProcessManager.h in Headers */,
index 9ccace0..5fef60e 100644 (file)
@@ -1,6 +1,6 @@
 /*
  * Copyright (C) 2014 Igalia S.L.
- * Copyright (C) 2016 Apple Inc. All rights reserved.
+ * Copyright (C) 2016-2018 Apple Inc. All rights reserved.
  *
  *  This library is free software; you can redistribute it and/or
  *  modify it under the terms of the GNU Lesser General Public
@@ -40,6 +40,8 @@ namespace WebKit {
 
 using namespace WebCore;
 
+static constexpr OptionSet<WebCore::ActivityState::Flag> focusedActiveWindow = { WebCore::ActivityState::IsFocused, WebCore::ActivityState::WindowIsActive };
+
 static uint64_t generateRequestID()
 {
     static uint64_t uniqueRequestID = 1;
@@ -53,6 +55,8 @@ UserMediaPermissionRequestManager::UserMediaPermissionRequestManager(WebPage& pa
 
 UserMediaPermissionRequestManager::~UserMediaPermissionRequestManager()
 {
+    if (m_monitoringActivityStateChange)
+        m_page.corePage()->removeActivityStateChangeObserver(*this);
     for (auto& sandboxExtension : m_userMediaDeviceSandboxExtensions)
         sandboxExtension.value->revoke();
 }
@@ -222,6 +226,77 @@ void UserMediaPermissionRequestManager::revokeUserMediaDeviceSandboxExtensions(c
     }
 }
 
+UserMediaClient::DeviceChangeObserverToken UserMediaPermissionRequestManager::addDeviceChangeObserver(WTF::Function<void()>&& observer)
+{
+    auto identifier = generateObjectIdentifier<WebCore::UserMediaClient::DeviceChangeObserverTokenType>();
+    m_deviceChangeObserverMap.add(identifier, WTFMove(observer));
+
+    if (!m_monitoringDeviceChange) {
+        m_monitoringDeviceChange = true;
+        m_page.send(Messages::WebPageProxy::BeginMonitoringCaptureDevices());
+    }
+    return identifier;
+}
+
+void UserMediaPermissionRequestManager::removeDeviceChangeObserver(UserMediaClient::DeviceChangeObserverToken token)
+{
+    bool wasRemoved = m_deviceChangeObserverMap.remove(token);
+    ASSERT_UNUSED(wasRemoved, wasRemoved);
+}
+
+void UserMediaPermissionRequestManager::captureDevicesChanged(DeviceAccessState accessState)
+{
+    // When new media input and/or output devices are made available, or any available input and/or
+    // output device becomes unavailable, the User Agent MUST run the following steps in browsing
+    // contexts where at least one of the following criteria are met, but in no other contexts:
+
+    // * The permission state of the "device-info" permission is "granted",
+    // * any of the input devices are attached to an active MediaStream in the browsing context, or
+    // * the active document is fully active and has focus.
+
+    bool isActive = (m_page.corePage()->activityState() & focusedActiveWindow) == focusedActiveWindow;
+    if (!isActive && accessState == DeviceAccessState::NoAccess) {
+        if (!isActive) {
+            if (!m_monitoringActivityStateChange) {
+                m_monitoringActivityStateChange = true;
+                m_page.corePage()->addActivityStateChangeObserver(*this);
+            }
+            m_pendingDeviceChangeEvent = true;
+            m_accessStateWhenDevicesChanged = accessState;
+        }
+        return;
+    }
+
+    auto identifiers = m_deviceChangeObserverMap.keys();
+    for (auto& identifier : identifiers) {
+        auto iterator = m_deviceChangeObserverMap.find(identifier);
+        if (iterator != m_deviceChangeObserverMap.end())
+            (iterator->value)();
+    }
+}
+
+void UserMediaPermissionRequestManager::activityStateDidChange(OptionSet<WebCore::ActivityState::Flag> oldActivityState, OptionSet<WebCore::ActivityState::Flag> newActivityState)
+{
+    if ((newActivityState & focusedActiveWindow) != focusedActiveWindow)
+        return;
+
+    RunLoop::main().dispatch([this, weakThis = makeWeakPtr(*this)]() mutable {
+        if (!weakThis || !m_monitoringActivityStateChange)
+            return;
+
+        m_monitoringActivityStateChange = false;
+        m_page.corePage()->removeActivityStateChangeObserver(*this);
+    });
+
+    if (!m_pendingDeviceChangeEvent)
+        return;
+
+    m_pendingDeviceChangeEvent = false;
+    auto accessState = m_accessStateWhenDevicesChanged;
+    m_accessStateWhenDevicesChanged = DeviceAccessState::NoAccess;
+    captureDevicesChanged(accessState);
+}
+
 } // namespace WebKit
 
 #endif // ENABLE(MEDIA_STREAM)
index a7efc8a..5746712 100644 (file)
@@ -1,6 +1,6 @@
 /*
  * Copyright (C) 2014 Igalia S.L.
- * Copyright (C) 2016 Apple Inc. All rights reserved.
+ * Copyright (C) 2016-2018 Apple Inc. All rights reserved.
  *
  *  This library is free software; you can redistribute it and/or
  *  modify it under the terms of the GNU Lesser General Public
@@ -24,6 +24,7 @@
 
 #include "MediaDeviceSandboxExtensions.h"
 #include "SandboxExtension.h"
+#include <WebCore/ActivityStateChangeObserver.h>
 #include <WebCore/MediaCanStartListener.h>
 #include <WebCore/MediaConstraints.h>
 #include <WebCore/MediaDevicesEnumerationRequest.h>
@@ -37,8 +38,9 @@ namespace WebKit {
 
 class WebPage;
 
-class UserMediaPermissionRequestManager
-    : private WebCore::MediaCanStartListener {
+enum class DeviceAccessState { NoAccess, SessionAccess, PersistentAccess };
+
+class UserMediaPermissionRequestManager : public CanMakeWeakPtr<UserMediaPermissionRequestManager>, private WebCore::MediaCanStartListener, private WebCore::ActivityStateChangeObserver {
 public:
     explicit UserMediaPermissionRequestManager(WebPage&);
     ~UserMediaPermissionRequestManager();
@@ -55,11 +57,19 @@ public:
     void grantUserMediaDeviceSandboxExtensions(MediaDeviceSandboxExtensions&&);
     void revokeUserMediaDeviceSandboxExtensions(const Vector<String>&);
 
+    WebCore::UserMediaClient::DeviceChangeObserverToken addDeviceChangeObserver(WTF::Function<void()>&&);
+    void removeDeviceChangeObserver(WebCore::UserMediaClient::DeviceChangeObserverToken);
+
+    void captureDevicesChanged(DeviceAccessState);
+
 private:
     void sendUserMediaRequest(WebCore::UserMediaRequest&);
 
     // WebCore::MediaCanStartListener
-    void mediaCanStart(WebCore::Document&) override;
+    void mediaCanStart(WebCore::Document&) final;
+
+    // WebCore::ActivityStateChangeObserver
+    void activityStateDidChange(OptionSet<WebCore::ActivityState::Flag> oldActivityState, OptionSet<WebCore::ActivityState::Flag> newActivityState) final;
 
     void removeMediaRequestFromMaps(WebCore::UserMediaRequest&);
 
@@ -73,10 +83,29 @@ private:
     HashMap<RefPtr<WebCore::MediaDevicesEnumerationRequest>, uint64_t> m_mediaDevicesEnumerationRequestToIDMap;
 
     HashMap<String, RefPtr<SandboxExtension>> m_userMediaDeviceSandboxExtensions;
+
+    HashMap<WebCore::UserMediaClient::DeviceChangeObserverToken, WTF::Function<void()>> m_deviceChangeObserverMap;
+    DeviceAccessState m_accessStateWhenDevicesChanged { DeviceAccessState::NoAccess };
+    bool m_monitoringDeviceChange { false };
+    bool m_pendingDeviceChangeEvent { false };
+    bool m_monitoringActivityStateChange { false };
 };
 
 } // namespace WebKit
 
+namespace WTF {
+
+template<> struct EnumTraits<WebKit::DeviceAccessState> {
+    using values = EnumValues<
+        WebKit::DeviceAccessState,
+        WebKit::DeviceAccessState::NoAccess,
+        WebKit::DeviceAccessState::SessionAccess,
+        WebKit::DeviceAccessState::PersistentAccess
+    >;
+};
+
+} // namespace WTF
+
 #endif // ENABLE(MEDIA_STREAM)
 
 #endif // UserMediaPermissionRequestManager_h
index 6f60574..0b06d63 100644 (file)
@@ -1,6 +1,6 @@
 /*
  * Copyright (C) 2014 Igalia S.L.
- * Copyright (C) 2016 Apple Inc. All rights reserved.
+ * Copyright (C) 2016-2018 Apple Inc. All rights reserved.
  *
  *  This library is free software; you can redistribute it and/or
  *  modify it under the terms of the GNU Lesser General Public
@@ -62,6 +62,16 @@ void WebUserMediaClient::cancelMediaDevicesEnumerationRequest(MediaDevicesEnumer
     m_page.userMediaPermissionRequestManager().cancelMediaDevicesEnumeration(request);
 }
 
+WebUserMediaClient::DeviceChangeObserverToken WebUserMediaClient::addDeviceChangeObserver(WTF::Function<void()>&& observer)
+{
+    return m_page.userMediaPermissionRequestManager().addDeviceChangeObserver(WTFMove(observer));
+}
+
+void WebUserMediaClient::removeDeviceChangeObserver(DeviceChangeObserverToken token)
+{
+    m_page.userMediaPermissionRequestManager().removeDeviceChangeObserver(token);
+}
+
 } // namespace WebKit;
 
 #endif // MEDIA_STREAM
index a6e3132..1093045 100644 (file)
@@ -1,6 +1,6 @@
 /*
  * Copyright (C) 2014 Igalia S.L.
- * Copyright (C) 2016 Apple Inc. All rights reserved.
+ * Copyright (C) 2016-2018 Apple Inc. All rights reserved.
  *
  *  This library is free software; you can redistribute it and/or
  *  modify it under the terms of the GNU Lesser General Public
@@ -42,6 +42,9 @@ private:
     void enumerateMediaDevices(WebCore::MediaDevicesEnumerationRequest&) final;
     void cancelMediaDevicesEnumerationRequest(WebCore::MediaDevicesEnumerationRequest&) final;
 
+    DeviceChangeObserverToken addDeviceChangeObserver(WTF::Function<void()>&&) final;
+    void removeDeviceChangeObserver(DeviceChangeObserverToken) final;
+
     void initializeFactories();
 
     WebPage& m_page;
index 82fff49..17a0064 100644 (file)
@@ -3739,6 +3739,12 @@ void WebPage::didCompleteMediaDeviceEnumeration(uint64_t userMediaID, const Vect
 {
     m_userMediaPermissionRequestManager->didCompleteMediaDeviceEnumeration(userMediaID, devices, WTFMove(deviceIdentifierHashSalt), originHasPersistentAccess);
 }
+
+void WebPage::captureDevicesChanged(DeviceAccessState accessState)
+{
+    m_userMediaPermissionRequestManager->captureDevicesChanged(accessState);
+}
+
 #if ENABLE(SANDBOX_EXTENSIONS)
 void WebPage::grantUserMediaDeviceSandboxExtensions(MediaDeviceSandboxExtensions&& extensions)
 {
index 2b27cc8..e51a604 100644 (file)
@@ -228,6 +228,7 @@ class WebTouchEvent;
 class WebCredentialsMessenger;
 class RemoteLayerTreeTransaction;
 
+enum class DeviceAccessState;
 enum FindOptions : uint16_t;
 enum class DragControllerAction;
 
@@ -565,6 +566,7 @@ public:
 #if ENABLE(MEDIA_STREAM)
     UserMediaPermissionRequestManager& userMediaPermissionRequestManager() { return *m_userMediaPermissionRequestManager; }
     void prepareToSendUserMediaPermissionRequest();
+    void captureDevicesChanged(DeviceAccessState);
 #endif
 
     void elementDidFocus(WebCore::Node*);
index 6436076..b71f28b 100644 (file)
@@ -318,6 +318,7 @@ messages -> WebPage LegacyReceiver {
     UserMediaAccessWasGranted(uint64_t userMediaID, WebCore::CaptureDevice audioDevice, WebCore::CaptureDevice videoDevice, String mediaDeviceIdentifierHashSalt)
     UserMediaAccessWasDenied(uint64_t userMediaID, uint64_t reason, String invalidConstraint)
     DidCompleteMediaDeviceEnumeration(uint64_t userMediaID, Vector<WebCore::CaptureDevice> devices, String mediaDeviceIdentifierHashSalt, bool hasPersistentAccess)
+    CaptureDevicesChanged(enum WebKit::DeviceAccessState accessState)
 #if ENABLE(SANDBOX_EXTENSIONS)
     GrantUserMediaDeviceSandboxExtensions(WebKit::MediaDeviceSandboxExtensions sandboxExtensions)
     RevokeUserMediaDeviceSandboxExtensions(Vector<String> sandboxExtensionIDs)