Title: [233162] trunk
Revision
233162
Author
you...@apple.com
Date
2018-06-25 12:19:06 -0700 (Mon, 25 Jun 2018)

Log Message

Add API to control mock media devices
https://bugs.webkit.org/show_bug.cgi?id=186958

Reviewed by Eric Carlson.

Source/WebCore:

Refactor code to introduce a MockDevice structure that can be used in multiple processes.
Update mock sources and center to use MockDevice.
Add API to update mock media devices.

Make MediaDevices an ActiveDOMObject so that it does not get collected when ondevicechange is set.

 Test: fast/mediastream/device-change-event-2.html

* Modules/mediastream/MediaDevices.cpp:
(WebCore::MediaDevices::MediaDevices):
(WebCore::MediaDevices::stop):
(WebCore::MediaDevices::scheduledEventTimerFired):
(WebCore::MediaDevices::hasPendingActivity const):
(WebCore::MediaDevices::activeDOMObjectName const):
(WebCore::MediaDevices::canSuspendForDocumentSuspension const):
* Modules/mediastream/MediaDevices.h:
* Modules/mediastream/MediaDevices.idl:
* WebCore.xcodeproj/project.pbxproj:
* platform/mediastream/RealtimeMediaSourceCenter.h:
* platform/mock/MockMediaDevice.h: Added.
(WebCore::MockMicrophoneProperties::encode const):
(WebCore::MockMicrophoneProperties::decode):
(WebCore::MockCameraProperties::encode const):
(WebCore::MockCameraProperties::decode):
(WebCore::MockDisplayProperties::encode const):
(WebCore::MockDisplayProperties::decode):
(WebCore::MockMediaDevice::isMicrophone const):
(WebCore::MockMediaDevice::isCamera const):
(WebCore::MockMediaDevice::isDisplay const):
(WebCore::MockMediaDevice::type const):
(WebCore::MockMediaDevice::encode const):
(WebCore::MockMediaDevice::decodeMockMediaDevice):
(WebCore::MockMediaDevice::decode):
* platform/mock/MockRealtimeAudioSource.cpp:
(WebCore::MockRealtimeAudioSource::startProducingData):
* platform/mock/MockRealtimeMediaSource.cpp:
(WebCore::defaultDevices):
(WebCore::devices):
(WebCore::deviceMap):
(WebCore::deviceListForDevice):
(WebCore::MockRealtimeMediaSource::createCaptureDevice):
(WebCore::MockRealtimeMediaSource::resetDevices):
(WebCore::MockRealtimeMediaSource::setDevices):
(WebCore::MockRealtimeMediaSource::addDevice):
(WebCore::MockRealtimeMediaSource::removeDevice):
(WebCore::MockRealtimeMediaSource::captureDeviceWithPersistentID):
(WebCore::MockRealtimeMediaSource::audioDevices):
(WebCore::MockRealtimeMediaSource::videoDevices):
(WebCore::MockRealtimeMediaSource::displayDevices):
(WebCore::MockRealtimeMediaSource::MockRealtimeMediaSource):
(WebCore::MockRealtimeMediaSource::initializeCapabilities):
(WebCore::MockRealtimeMediaSource::initializeSettings):
(WebCore::MockRealtimeMediaSource::settings const):
(WebCore::MockRealtimeMediaSource::supportedConstraints):
* platform/mock/MockRealtimeMediaSource.h:
(WebCore::MockRealtimeMediaSource::device const):
* platform/mock/MockRealtimeMediaSourceCenter.cpp:
(WebCore::MockRealtimeMediaSourceCenter::singleton):
(WebCore::MockRealtimeMediaSourceCenter::setMockRealtimeMediaSourceCenterEnabled):
(WebCore::MockRealtimeMediaSourceCenter::setDevices):
(WebCore::MockRealtimeMediaSourceCenter::addDevice):
(WebCore::MockRealtimeMediaSourceCenter::removeDevice):
* platform/mock/MockRealtimeMediaSourceCenter.h:
* platform/mock/MockRealtimeVideoSource.cpp:
(WebCore::MockRealtimeVideoSource::MockRealtimeVideoSource):
(WebCore::MockRealtimeVideoSource::initializeCapabilities):
(WebCore::MockRealtimeVideoSource::drawText):
(WebCore::MockRealtimeVideoSource::generateFrame):
* platform/mock/MockRealtimeVideoSource.h:
(WebCore::MockRealtimeVideoSource::mockCamera const):
(WebCore::MockRealtimeVideoSource::mockScreen const):

Source/WebKit:

Add API to clear, set, remove and reset mock media devices.
The mock media center of UIProcess and all WebProcesses are updated.

* CMakeLists.txt:
* UIProcess/API/C/WKMockMediaDevice.cpp: Added.
(typeFromString):
(WKAddMockMediaDevice):
(WKClearMockMediaDevices):
(WKRemoveMockMediaDevice):
(WKResetMockMediaDevices):
* UIProcess/API/C/WKMockMediaDevice.h: Added.
* UIProcess/WebProcessPool.cpp:
(WebKit::WebProcessPool::addMockMediaDevice):
(WebKit::WebProcessPool::clearMockMediaDevices):
(WebKit::WebProcessPool::removeMockMediaDevice):
(WebKit::WebProcessPool::resetMockMediaDevices):
* UIProcess/WebProcessPool.h:
* WebKit.xcodeproj/project.pbxproj:
* WebProcess/WebProcess.cpp:
(WebKit::WebProcess::addMockMediaDevice):
(WebKit::WebProcess::clearMockMediaDevices):
(WebKit::WebProcess::removeMockMediaDevice):
(WebKit::WebProcess::resetMockMediaDevices):
* WebProcess/WebProcess.h:
* WebProcess/WebProcess.messages.in:

Tools:

Add test runner API to clear/add/remove/reset mock media devices.

* WebKitTestRunner/InjectedBundle/Bindings/TestRunner.idl:
* WebKitTestRunner/InjectedBundle/TestRunner.cpp:
(WTR::TestRunner::addMockMediaDevice):
(WTR::TestRunner::addMockCameraDevice):
(WTR::TestRunner::addMockMicrophoneDevice):
(WTR::TestRunner::addMockScreenDevice):
(WTR::TestRunner::clearMockMediaDevices):
(WTR::TestRunner::removeMockMediaDevice):
(WTR::TestRunner::resetMockMediaDevices):
* WebKitTestRunner/InjectedBundle/TestRunner.h:
* WebKitTestRunner/TestController.cpp:
(WTR::TestController::addMockMediaDevice):
(WTR::TestController::clearMockMediaDevices):
(WTR::TestController::removeMockMediaDevice):
(WTR::TestController::resetMockMediaDevices):
* WebKitTestRunner/TestController.h:
* WebKitTestRunner/TestInvocation.cpp:
(WTR::TestInvocation::didReceiveSynchronousMessageFromInjectedBundle):

LayoutTests:

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

Modified Paths

Added Paths

Diff

Modified: trunk/LayoutTests/ChangeLog (233161 => 233162)


--- trunk/LayoutTests/ChangeLog	2018-06-25 18:53:34 UTC (rev 233161)
+++ trunk/LayoutTests/ChangeLog	2018-06-25 19:19:06 UTC (rev 233162)
@@ -1,3 +1,13 @@
+2018-06-25  Youenn Fablet  <you...@apple.com>
+
+        Add API to control mock media devices
+        https://bugs.webkit.org/show_bug.cgi?id=186958
+
+        Reviewed by Eric Carlson.
+
+        * fast/mediastream/device-change-event-2-expected.txt: Added.
+        * fast/mediastream/device-change-event-2.html: Added.
+
 2018-06-25  Antoine Quint  <grao...@apple.com>
 
         [Web Animations] Make imported/mozilla/css-animations/test_animation-pausing.html pass reliably

Added: trunk/LayoutTests/fast/mediastream/device-change-event-2-expected.txt (0 => 233162)


--- trunk/LayoutTests/fast/mediastream/device-change-event-2-expected.txt	                        (rev 0)
+++ trunk/LayoutTests/fast/mediastream/device-change-event-2-expected.txt	2018-06-25 19:19:06 UTC (rev 233162)
@@ -0,0 +1,3 @@
+
+PASS 'devicechange' event fired when device list changes 
+

Added: trunk/LayoutTests/fast/mediastream/device-change-event-2.html (0 => 233162)


--- trunk/LayoutTests/fast/mediastream/device-change-event-2.html	                        (rev 0)
+++ trunk/LayoutTests/fast/mediastream/device-change-event-2.html	2018-06-25 19:19:06 UTC (rev 233162)
@@ -0,0 +1,58 @@
+<!DOCTYPE html>
+<html>
+<head>
+    <meta charset="utf-8">
+    <title>Testing local audio capture playback causes "playing" event to fire</title>
+    <script src=""
+    <script src=""
+    <script>
+    let deviceIds = [];
+    promise_test(async (test) => {
+        if (!window.testRunner)
+            return Promise.reject("test requires internal API");
+
+        test.add_cleanup(() => { testRunner.resetMockMediaDevices(); });
+
+        testRunner.setUserMediaPermission(true);
+
+        await navigator.mediaDevices.getUserMedia({ audio:true, video:true });
+
+        let devices = await navigator.mediaDevices.enumerateDevices();
+
+        assert_true(!!devices.length, "check there are some devices");
+
+        testRunner.clearMockMediaDevices();
+
+        devices = await navigator.mediaDevices.enumerateDevices();
+        assert_false(!!devices.length, "check there are no more devices");
+
+        await new Promise((resolve, reject) => {
+            navigator.mediaDevices._ondevicechange_ = resolve;
+            setTimeout(() => {
+                console.log("event 1 taking a long time");
+                resolve();
+            }, 5000);
+            testRunner.addMockCameraDevice("id1", "my camera");
+        });
+        devices = await navigator.mediaDevices.enumerateDevices();
+        assert_equals(devices[0].kind, "videoinput");
+        assert_equals(devices[0].label, "my camera");
+
+        await new Promise((resolve, reject) => {
+            navigator.mediaDevices._ondevicechange_ = resolve;
+            setTimeout(() => {
+                console.log("event 2 taking a long time");
+                resolve();
+            }, 5000);
+            testRunner.addMockMicrophoneDevice("id2", "my mic");
+        });
+        devices = await navigator.mediaDevices.enumerateDevices();
+        assert_equals(devices[0].kind, "audioinput");
+        assert_equals(devices[0].label, "my mic");
+
+    }, "'devicechange' event fired when device list changes");
+    </script>
+</head>
+<body>
+</body>
+</html>

Modified: trunk/Source/WebCore/ChangeLog (233161 => 233162)


--- trunk/Source/WebCore/ChangeLog	2018-06-25 18:53:34 UTC (rev 233161)
+++ trunk/Source/WebCore/ChangeLog	2018-06-25 19:19:06 UTC (rev 233162)
@@ -1,3 +1,82 @@
+2018-06-25  Youenn Fablet  <you...@apple.com>
+
+        Add API to control mock media devices
+        https://bugs.webkit.org/show_bug.cgi?id=186958
+
+        Reviewed by Eric Carlson.
+
+        Refactor code to introduce a MockDevice structure that can be used in multiple processes.
+        Update mock sources and center to use MockDevice.
+        Add API to update mock media devices.
+
+        Make MediaDevices an ActiveDOMObject so that it does not get collected when ondevicechange is set.
+
+         Test: fast/mediastream/device-change-event-2.html
+
+        * Modules/mediastream/MediaDevices.cpp:
+        (WebCore::MediaDevices::MediaDevices):
+        (WebCore::MediaDevices::stop):
+        (WebCore::MediaDevices::scheduledEventTimerFired):
+        (WebCore::MediaDevices::hasPendingActivity const):
+        (WebCore::MediaDevices::activeDOMObjectName const):
+        (WebCore::MediaDevices::canSuspendForDocumentSuspension const):
+        * Modules/mediastream/MediaDevices.h:
+        * Modules/mediastream/MediaDevices.idl:
+        * WebCore.xcodeproj/project.pbxproj:
+        * platform/mediastream/RealtimeMediaSourceCenter.h:
+        * platform/mock/MockMediaDevice.h: Added.
+        (WebCore::MockMicrophoneProperties::encode const):
+        (WebCore::MockMicrophoneProperties::decode):
+        (WebCore::MockCameraProperties::encode const):
+        (WebCore::MockCameraProperties::decode):
+        (WebCore::MockDisplayProperties::encode const):
+        (WebCore::MockDisplayProperties::decode):
+        (WebCore::MockMediaDevice::isMicrophone const):
+        (WebCore::MockMediaDevice::isCamera const):
+        (WebCore::MockMediaDevice::isDisplay const):
+        (WebCore::MockMediaDevice::type const):
+        (WebCore::MockMediaDevice::encode const):
+        (WebCore::MockMediaDevice::decodeMockMediaDevice):
+        (WebCore::MockMediaDevice::decode):
+        * platform/mock/MockRealtimeAudioSource.cpp:
+        (WebCore::MockRealtimeAudioSource::startProducingData):
+        * platform/mock/MockRealtimeMediaSource.cpp:
+        (WebCore::defaultDevices):
+        (WebCore::devices):
+        (WebCore::deviceMap):
+        (WebCore::deviceListForDevice):
+        (WebCore::MockRealtimeMediaSource::createCaptureDevice):
+        (WebCore::MockRealtimeMediaSource::resetDevices):
+        (WebCore::MockRealtimeMediaSource::setDevices):
+        (WebCore::MockRealtimeMediaSource::addDevice):
+        (WebCore::MockRealtimeMediaSource::removeDevice):
+        (WebCore::MockRealtimeMediaSource::captureDeviceWithPersistentID):
+        (WebCore::MockRealtimeMediaSource::audioDevices):
+        (WebCore::MockRealtimeMediaSource::videoDevices):
+        (WebCore::MockRealtimeMediaSource::displayDevices):
+        (WebCore::MockRealtimeMediaSource::MockRealtimeMediaSource):
+        (WebCore::MockRealtimeMediaSource::initializeCapabilities):
+        (WebCore::MockRealtimeMediaSource::initializeSettings):
+        (WebCore::MockRealtimeMediaSource::settings const):
+        (WebCore::MockRealtimeMediaSource::supportedConstraints):
+        * platform/mock/MockRealtimeMediaSource.h:
+        (WebCore::MockRealtimeMediaSource::device const):
+        * platform/mock/MockRealtimeMediaSourceCenter.cpp:
+        (WebCore::MockRealtimeMediaSourceCenter::singleton):
+        (WebCore::MockRealtimeMediaSourceCenter::setMockRealtimeMediaSourceCenterEnabled):
+        (WebCore::MockRealtimeMediaSourceCenter::setDevices):
+        (WebCore::MockRealtimeMediaSourceCenter::addDevice):
+        (WebCore::MockRealtimeMediaSourceCenter::removeDevice):
+        * platform/mock/MockRealtimeMediaSourceCenter.h:
+        * platform/mock/MockRealtimeVideoSource.cpp:
+        (WebCore::MockRealtimeVideoSource::MockRealtimeVideoSource):
+        (WebCore::MockRealtimeVideoSource::initializeCapabilities):
+        (WebCore::MockRealtimeVideoSource::drawText):
+        (WebCore::MockRealtimeVideoSource::generateFrame):
+        * platform/mock/MockRealtimeVideoSource.h:
+        (WebCore::MockRealtimeVideoSource::mockCamera const):
+        (WebCore::MockRealtimeVideoSource::mockScreen const):
+
 2018-06-25  Simon Fraser  <simon.fra...@apple.com>
 
         AutoTableLayout wastes 52KB of Vector capacity on nytimes.com

Modified: trunk/Source/WebCore/Modules/mediastream/MediaDevices.cpp (233161 => 233162)


--- trunk/Source/WebCore/Modules/mediastream/MediaDevices.cpp	2018-06-25 18:53:34 UTC (rev 233161)
+++ trunk/Source/WebCore/Modules/mediastream/MediaDevices.cpp	2018-06-25 19:19:06 UTC (rev 233162)
@@ -47,8 +47,9 @@
 namespace WebCore {
 
 inline MediaDevices::MediaDevices(Document& document)
-    : ContextDestructionObserver(&document)
+    : ActiveDOMObject(&document)
     , m_scheduledEventTimer(*this, &MediaDevices::scheduledEventTimerFired)
+    , m_eventNames(eventNames())
 {
     m_deviceChangedToken = RealtimeMediaSourceCenter::singleton().addDevicesChangedObserver([weakThis = makeWeakPtr(*this), this]() {
 
@@ -61,6 +62,8 @@
             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");
     static_assert(static_cast<size_t>(MediaDevices::DisplayCaptureSurfaceType::Window) == static_cast<size_t>(RealtimeMediaSourceSettings::DisplaySurfaceType::Window), "MediaDevices::DisplayCaptureSurfaceType::Window is not RealtimeMediaSourceSettings::DisplaySurfaceType::Window as expected");
     static_assert(static_cast<size_t>(MediaDevices::DisplayCaptureSurfaceType::Application) == static_cast<size_t>(RealtimeMediaSourceSettings::DisplaySurfaceType::Application), "MediaDevices::DisplayCaptureSurfaceType::Application is not RealtimeMediaSourceSettings::DisplaySurfaceType::Application as expected");
@@ -67,10 +70,12 @@
     static_assert(static_cast<size_t>(MediaDevices::DisplayCaptureSurfaceType::Browser) == static_cast<size_t>(RealtimeMediaSourceSettings::DisplaySurfaceType::Browser), "MediaDevices::DisplayCaptureSurfaceType::Browser is not RealtimeMediaSourceSettings::DisplaySurfaceType::Browser as expected");
 }
 
-MediaDevices::~MediaDevices()
+MediaDevices::~MediaDevices() = default;
+
+void MediaDevices::stop()
 {
     if (m_deviceChangedToken)
-        RealtimeMediaSourceCenter::singleton().removeDevicesChangedObserver(m_deviceChangedToken.value());
+        RealtimeMediaSourceCenter::singleton().removeDevicesChangedObserver(m_deviceChangedToken);
 }
 
 Ref<MediaDevices> MediaDevices::create(Document& document)
@@ -157,9 +162,25 @@
 
 void MediaDevices::scheduledEventTimerFired()
 {
-    dispatchEvent(Event::create(eventNames().devicechangeEvent, false, false));
+    if (scriptExecutionContext())
+        dispatchEvent(Event::create(eventNames().devicechangeEvent, false, false));
 }
 
+bool MediaDevices::hasPendingActivity() const
+{
+    return scriptExecutionContext() && hasEventListeners(m_eventNames.devicechangeEvent);
+}
+
+const char* MediaDevices::activeDOMObjectName() const
+{
+    return "MediaDevices";
+}
+
+bool MediaDevices::canSuspendForDocumentSuspension() const
+{
+    return true;
+}
+
 } // namespace WebCore
 
 #endif // ENABLE(MEDIA_STREAM)

Modified: trunk/Source/WebCore/Modules/mediastream/MediaDevices.h (233161 => 233162)


--- trunk/Source/WebCore/Modules/mediastream/MediaDevices.h	2018-06-25 18:53:34 UTC (rev 233161)
+++ trunk/Source/WebCore/Modules/mediastream/MediaDevices.h	2018-06-25 19:19:06 UTC (rev 233162)
@@ -33,6 +33,8 @@
 
 #if ENABLE(MEDIA_STREAM)
 
+#include "ActiveDOMObject.h"
+#include "EventNames.h"
 #include "EventTarget.h"
 #include "ExceptionOr.h"
 #include "JSDOMPromiseDeferred.h"
@@ -49,7 +51,7 @@
 
 struct MediaTrackSupportedConstraints;
 
-class MediaDevices : public RefCounted<MediaDevices>, public ContextDestructionObserver, public EventTargetWithInlineData, public CanMakeWeakPtr<MediaDevices> {
+class MediaDevices : public RefCounted<MediaDevices>, public ActiveDOMObject, public EventTargetWithInlineData, public CanMakeWeakPtr<MediaDevices> {
 public:
     static Ref<MediaDevices> create(Document&);
 
@@ -84,14 +86,23 @@
 
     void scheduledEventTimerFired();
 
+    friend class JSMediaDevicesOwner;
+
+    // ActiveDOMObject
+    const char* activeDOMObjectName() const final;
+    bool canSuspendForDocumentSuspension() const final;
+    void stop() final;
+    bool hasPendingActivity() const final;
+
     // EventTargetWithInlineData.
-    EventTargetInterface eventTargetInterface() const override { return MediaDevicesEventTargetInterfaceType; }
-    ScriptExecutionContext* scriptExecutionContext() const final { return m_scriptExecutionContext; }
-    void refEventTarget() override { ref(); }
-    void derefEventTarget() override { deref(); }
+    EventTargetInterface eventTargetInterface() const final { return MediaDevicesEventTargetInterfaceType; }
+    ScriptExecutionContext* scriptExecutionContext() const final { return ActiveDOMObject::scriptExecutionContext(); }
+    void refEventTarget() final { ref(); }
+    void derefEventTarget() final { deref(); }
 
     Timer m_scheduledEventTimer;
-    std::optional<RealtimeMediaSourceCenter::DevicesChangedObserverToken> m_deviceChangedToken;
+    RealtimeMediaSourceCenter::DevicesChangedObserverToken m_deviceChangedToken;
+    const EventNames& m_eventNames; // Need to cache this so we can use it from GC threads.
 };
 
 } // namespace WebCore

Modified: trunk/Source/WebCore/Modules/mediastream/MediaDevices.idl (233161 => 233162)


--- trunk/Source/WebCore/Modules/mediastream/MediaDevices.idl	2018-06-25 18:53:34 UTC (rev 233161)
+++ trunk/Source/WebCore/Modules/mediastream/MediaDevices.idl	2018-06-25 19:19:06 UTC (rev 233162)
@@ -30,6 +30,7 @@
 
 // FIXME 169871: should be subclass of EventTarget
 [
+    ActiveDOMObject,
     Conditional=MEDIA_STREAM,
     NoInterfaceObject,
 ] interface MediaDevices {

Modified: trunk/Source/WebCore/WebCore.xcodeproj/project.pbxproj (233161 => 233162)


--- trunk/Source/WebCore/WebCore.xcodeproj/project.pbxproj	2018-06-25 18:53:34 UTC (rev 233161)
+++ trunk/Source/WebCore/WebCore.xcodeproj/project.pbxproj	2018-06-25 19:19:06 UTC (rev 233162)
@@ -1064,6 +1064,7 @@
 		4138D3351244054800323D33 /* EventContext.h in Headers */ = {isa = PBXBuildFile; fileRef = 4138D3331244054800323D33 /* EventContext.h */; };
 		4138F8581D253F0E001CB61E /* JSDOMIterator.h in Headers */ = {isa = PBXBuildFile; fileRef = 4138F8561D253EEE001CB61E /* JSDOMIterator.h */; settings = {ATTRIBUTES = (Private, ); }; };
 		413C2C341BC29A8F0075204C /* JSDOMConstructor.h in Headers */ = {isa = PBXBuildFile; fileRef = 413C2C331BC29A7B0075204C /* JSDOMConstructor.h */; };
+		413CCD4A20DE034F0065A21A /* MockMediaDevice.h in Headers */ = {isa = PBXBuildFile; fileRef = 413CCD4820DE013C0065A21A /* MockMediaDevice.h */; settings = {ATTRIBUTES = (Private, ); }; };
 		413E00791DB0E4F2002341D2 /* MemoryRelease.h in Headers */ = {isa = PBXBuildFile; fileRef = 413E00781DB0E4DE002341D2 /* MemoryRelease.h */; settings = {ATTRIBUTES = (Private, ); }; };
 		414B82051D6DF0E50077EBE3 /* StructuredClone.h in Headers */ = {isa = PBXBuildFile; fileRef = 414B82031D6DF0D90077EBE3 /* StructuredClone.h */; };
 		414DEDE71F9FE91E0047C40D /* EmptyFrameLoaderClient.h in Headers */ = {isa = PBXBuildFile; fileRef = 414DEDE51F9FE9150047C40D /* EmptyFrameLoaderClient.h */; settings = {ATTRIBUTES = (Private, ); }; };
@@ -7202,6 +7203,7 @@
 		4138F8551D253EEE001CB61E /* JSDOMIterator.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = JSDOMIterator.cpp; sourceTree = "<group>"; };
 		4138F8561D253EEE001CB61E /* JSDOMIterator.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = JSDOMIterator.h; sourceTree = "<group>"; };
 		413C2C331BC29A7B0075204C /* JSDOMConstructor.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = JSDOMConstructor.h; sourceTree = "<group>"; };
+		413CCD4820DE013C0065A21A /* MockMediaDevice.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MockMediaDevice.h; sourceTree = "<group>"; };
 		413E00771DB0E4DE002341D2 /* MemoryRelease.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = MemoryRelease.cpp; sourceTree = "<group>"; };
 		413E00781DB0E4DE002341D2 /* MemoryRelease.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MemoryRelease.h; sourceTree = "<group>"; };
 		413E007B1DB0E707002341D2 /* MemoryReleaseCocoa.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = MemoryReleaseCocoa.mm; sourceTree = "<group>"; };
@@ -18774,6 +18776,7 @@
 				077B64151B95F703003E9AD5 /* MediaPlaybackTargetMock.h */,
 				077B64101B94F12E003E9AD5 /* MediaPlaybackTargetPickerMock.cpp */,
 				077B64111B94F12E003E9AD5 /* MediaPlaybackTargetPickerMock.h */,
+				413CCD4820DE013C0065A21A /* MockMediaDevice.h */,
 				07D6A4F11BED5F8800174146 /* MockRealtimeAudioSource.cpp */,
 				07D6A4F21BED5F8800174146 /* MockRealtimeAudioSource.h */,
 				07D6A4ED1BECF2D200174146 /* MockRealtimeMediaSource.cpp */,
@@ -29423,6 +29426,7 @@
 				CDF4B7201E03BF6F00E235A2 /* MockCDMFactory.idl in Headers */,
 				51058AE01D67C229009A538C /* MockGamepad.h in Headers */,
 				51058AE21D67C229009A538C /* MockGamepadProvider.h in Headers */,
+				413CCD4A20DE034F0065A21A /* MockMediaDevice.h in Headers */,
 				CDF2B0131820540600F2B424 /* MockMediaPlayerMediaSource.h in Headers */,
 				CDF2B0151820540600F2B424 /* MockMediaSourcePrivate.h in Headers */,
 				07D6A4F41BED5F8800174146 /* MockRealtimeAudioSource.h in Headers */,

Modified: trunk/Source/WebCore/platform/mediastream/RealtimeMediaSourceCenter.h (233161 => 233162)


--- trunk/Source/WebCore/platform/mediastream/RealtimeMediaSourceCenter.h	2018-06-25 18:53:34 UTC (rev 233161)
+++ trunk/Source/WebCore/platform/mediastream/RealtimeMediaSourceCenter.h	2018-06-25 19:19:06 UTC (rev 233162)
@@ -88,7 +88,6 @@
     using DevicesChangedObserverToken = unsigned;
     DevicesChangedObserverToken addDevicesChangedObserver(std::function<void()>&&);
     void removeDevicesChangedObserver(DevicesChangedObserverToken);
-    void captureDevicesChanged();
 
     void setVideoCapturePageState(bool, bool);
 
@@ -95,6 +94,8 @@
 protected:
     RealtimeMediaSourceCenter();
 
+    void captureDevicesChanged();
+
     static RealtimeMediaSourceCenter& platformCenter();
     RealtimeMediaSourceSupportedConstraints m_supportedConstraints;
 

Added: trunk/Source/WebCore/platform/mock/MockMediaDevice.h (0 => 233162)


--- trunk/Source/WebCore/platform/mock/MockMediaDevice.h	                        (rev 0)
+++ trunk/Source/WebCore/platform/mock/MockMediaDevice.h	2018-06-25 19:19:06 UTC (rev 233162)
@@ -0,0 +1,187 @@
+/*
+ * Copyright (C) 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
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer
+ *    in the documentation and/or other materials provided with the
+ *    distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#pragma once
+
+#if ENABLE(MEDIA_STREAM)
+
+#include "CaptureDevice.h"
+#include "RealtimeMediaSource.h"
+
+namespace WebCore {
+
+struct MockMicrophoneProperties {
+    template<class Encoder>
+    void encode(Encoder& encoder) const
+    {
+        encoder << static_cast<int32_t>(defaultSampleRate);
+    }
+
+    template <class Decoder>
+    static std::optional<MockMicrophoneProperties> decode(Decoder& decoder)
+    {
+        std::optional<int32_t> defaultSampleRate;
+        decoder >> defaultSampleRate;
+        if (!defaultSampleRate)
+            return std::nullopt;
+        return MockMicrophoneProperties { *defaultSampleRate };
+    }
+
+    int defaultSampleRate { 44100 };
+};
+
+// FIXME: Add support for other properties and serialization of colors.
+struct MockCameraProperties {
+    template<class Encoder>
+    void encode(Encoder& encoder) const
+    {
+        encoder << defaultFrameRate;
+        encoder << facingModeCapability;
+    }
+
+    template <class Decoder>
+    static std::optional<MockCameraProperties> decode(Decoder& decoder)
+    {
+        std::optional<double> defaultFrameRate;
+        decoder >> defaultFrameRate;
+        if (!defaultFrameRate)
+            return std::nullopt;
+
+        std::optional<RealtimeMediaSourceSettings::VideoFacingMode> facingModeCapability;
+        decoder >> facingModeCapability;
+        if (!facingModeCapability)
+            return std::nullopt;
+
+        return MockCameraProperties { *defaultFrameRate, *facingModeCapability, Color::black };
+    }
+
+    double defaultFrameRate { 30 };
+    RealtimeMediaSourceSettings::VideoFacingMode facingModeCapability { RealtimeMediaSourceSettings::VideoFacingMode::User };
+    Color fillColor { Color::black };
+};
+
+struct MockDisplayProperties {
+    template<class Encoder>
+    void encode(Encoder& encoder) const
+    {
+        encoder << defaultFrameRate;
+    }
+
+    template <class Decoder>
+    static std::optional<MockDisplayProperties> decode(Decoder& decoder)
+    {
+        std::optional<double> defaultFrameRate;
+        decoder >> defaultFrameRate;
+        if (!defaultFrameRate)
+            return std::nullopt;
+
+        return MockDisplayProperties { *defaultFrameRate, Color::lightGray };
+    }
+
+    double defaultFrameRate { 30 };
+    Color fillColor { Color::lightGray };
+};
+
+struct MockMediaDevice {
+    bool isMicrophone() const { return WTF::holds_alternative<MockMicrophoneProperties>(properties); }
+    bool isCamera() const { return WTF::holds_alternative<MockCameraProperties>(properties); }
+    bool isDisplay() const { return WTF::holds_alternative<MockDisplayProperties>(properties); }
+
+    CaptureDevice::DeviceType type() const
+    {
+        if (isMicrophone())
+            return CaptureDevice::DeviceType::Microphone;
+        if (isCamera())
+            return CaptureDevice::DeviceType::Camera;
+        ASSERT(isDisplay());
+        return CaptureDevice::DeviceType::Screen;
+    }
+
+    template<class Encoder>
+    void encode(Encoder& encoder) const
+    {
+        encoder << persistentId;
+        encoder << label;
+        switchOn(properties, [&](const MockMicrophoneProperties& properties) {
+            encoder << (uint8_t)1;
+            encoder << properties;
+        }, [&](const MockCameraProperties& properties) {
+            encoder << (uint8_t)2;
+            encoder << properties;
+        }, [&](const MockDisplayProperties& properties) {
+            encoder << (uint8_t)3;
+            encoder << properties;
+        });
+    }
+
+    template <typename Properties, typename Decoder>
+    static std::optional<MockMediaDevice> decodeMockMediaDevice(Decoder& decoder, String&& persistentId, String&& label)
+    {
+        std::optional<Properties> properties;
+        decoder >> properties;
+        if (!properties)
+            return std::nullopt;
+        return MockMediaDevice { WTFMove(persistentId), WTFMove(label), WTFMove(*properties) };
+    }
+
+    template <class Decoder>
+    static std::optional<MockMediaDevice> decode(Decoder& decoder)
+    {
+        std::optional<String> persistentId;
+        decoder >> persistentId;
+        if (!persistentId)
+            return std::nullopt;
+
+        std::optional<String> label;
+        decoder >> label;
+        if (!label)
+            return std::nullopt;
+
+        std::optional<uint8_t> index;
+        decoder >> index;
+        if (!index)
+            return std::nullopt;
+
+        switch (*index) {
+        case 1:
+            return decodeMockMediaDevice<MockMicrophoneProperties>(decoder, WTFMove(*persistentId), WTFMove(*label));
+        case 2:
+            return decodeMockMediaDevice<MockCameraProperties>(decoder, WTFMove(*persistentId), WTFMove(*label));
+        case 3:
+            return decodeMockMediaDevice<MockDisplayProperties>(decoder, WTFMove(*persistentId), WTFMove(*label));
+        }
+        return std::nullopt;
+    }
+
+    String persistentId;
+    String label;
+    Variant<MockMicrophoneProperties, MockCameraProperties, MockDisplayProperties> properties;
+};
+
+} // namespace WebCore
+
+#endif // ENABLE(MEDIA_STREAM)

Modified: trunk/Source/WebCore/platform/mock/MockRealtimeAudioSource.cpp (233161 => 233162)


--- trunk/Source/WebCore/platform/mock/MockRealtimeAudioSource.cpp	2018-06-25 18:53:34 UTC (rev 233161)
+++ trunk/Source/WebCore/platform/mock/MockRealtimeAudioSource.cpp	2018-06-25 19:19:06 UTC (rev 233162)
@@ -118,7 +118,7 @@
 #endif
 
     if (!sampleRate())
-        setSampleRate(device() == MockRealtimeMediaSource::MockDevice::Microphone1 ? 44100 : 48000);
+        setSampleRate(WTF::get<MockMicrophoneProperties>(device().properties).defaultSampleRate);
 
     m_startTime = MonotonicTime::now();
     m_timer.startRepeating(renderInterval());

Modified: trunk/Source/WebCore/platform/mock/MockRealtimeMediaSource.cpp (233161 => 233162)


--- trunk/Source/WebCore/platform/mock/MockRealtimeMediaSource.cpp	2018-06-25 18:53:34 UTC (rev 233161)
+++ trunk/Source/WebCore/platform/mock/MockRealtimeMediaSource.cpp	2018-06-25 19:19:06 UTC (rev 233162)
@@ -44,116 +44,163 @@
 
 namespace WebCore {
 
-struct MockDeviceInfo {
-    ASCIILiteral id { ASCIILiteral::null() };
-    CaptureDevice::DeviceType type;
-    ASCIILiteral name { ASCIILiteral::null() };
-    MockRealtimeMediaSource::MockDevice device;
-};
+static inline Vector<MockMediaDevice> defaultDevices()
+{
+    return Vector<MockMediaDevice> {
+        MockMediaDevice { "239c24b0-2b15-11e3-8224-0800200c9a66"_s, "Mock audio device 1"_s, MockMicrophoneProperties { 44100 } },
+        MockMediaDevice { "239c24b1-2b15-11e3-8224-0800200c9a66"_s, "Mock audio device 2"_s, MockMicrophoneProperties { 48000 } },
 
-static const HashMap<String, MockDeviceInfo>& deviceMap()
+        MockMediaDevice { "239c24b2-2b15-11e3-8224-0800200c9a66"_s, "Mock video device 1"_s, MockCameraProperties { 30, RealtimeMediaSourceSettings::VideoFacingMode::User, Color::black } },
+        MockMediaDevice { "239c24b3-2b15-11e3-8224-0800200c9a66"_s, "Mock video device 2"_s, MockCameraProperties { 15, RealtimeMediaSourceSettings::VideoFacingMode::Environment, Color::darkGray } },
+
+        MockMediaDevice { "SCREEN-1"_s, "Mock screen device 1"_s, MockDisplayProperties { 30, Color::lightGray } },
+        MockMediaDevice { "SCREEN-2"_s, "Mock screen device 2"_s, MockDisplayProperties { 10, Color::yellow } }
+    };
+}
+
+static Vector<MockMediaDevice>& devices()
 {
-    static const auto infoMap = makeNeverDestroyed([] {
-        static const MockDeviceInfo devices[] = {
-            { "239c24b0-2b15-11e3-8224-0800200c9a66"_s, CaptureDevice::DeviceType::Microphone, "Mock audio device 1"_s, MockRealtimeMediaSource::MockDevice::Microphone1 },
-            { "239c24b1-2b15-11e3-8224-0800200c9a66"_s, CaptureDevice::DeviceType::Microphone, "Mock audio device 2"_s, MockRealtimeMediaSource::MockDevice::Microphone2 },
+    static auto devices = makeNeverDestroyed([] {
+        return defaultDevices();
+    }());
+    return devices;
+}
 
-            { "239c24b2-2b15-11e3-8224-0800200c9a66"_s, CaptureDevice::DeviceType::Camera, "Mock video device 1"_s, MockRealtimeMediaSource::MockDevice::Camera1 },
-            { "239c24b3-2b15-11e3-8224-0800200c9a66"_s, CaptureDevice::DeviceType::Camera, "Mock video device 2"_s, MockRealtimeMediaSource::MockDevice::Camera2 },
+static HashMap<String, MockMediaDevice>& deviceMap()
+{
+    static auto map = makeNeverDestroyed([] {
+        HashMap<String, MockMediaDevice> map;
+        for (auto& device : devices())
+            map.add(device.persistentId, device);
 
-            { "SCREEN-1"_s, CaptureDevice::DeviceType::Screen, "Mock screen device 1"_s, MockRealtimeMediaSource::MockDevice::Screen1 },
-            { "SCREEN-2"_s, CaptureDevice::DeviceType::Screen, "Mock screen device 2"_s, MockRealtimeMediaSource::MockDevice::Screen2 },
-        };
-
-        HashMap<String, MockDeviceInfo> map;
-        for (auto& info : devices)
-            map.add(info.id, info);
         return map;
     }());
+    return map;
+}
 
-    return infoMap;
+static inline Vector<CaptureDevice>& deviceListForDevice(const MockMediaDevice& device)
+{
+    if (device.isMicrophone())
+        return MockRealtimeAudioSource::audioDevices();
+    if (device.isCamera())
+        return MockRealtimeAudioSource::videoDevices();
+
+    ASSERT(device.isDisplay());
+    return MockRealtimeAudioSource::displayDevices();
 }
 
-std::optional<CaptureDevice> MockRealtimeMediaSource::captureDeviceWithPersistentID(CaptureDevice::DeviceType type, const String& id)
+void MockRealtimeMediaSource::createCaptureDevice(const MockMediaDevice& device)
 {
-    ASSERT(!id.isEmpty());
+    deviceListForDevice(device).append(captureDeviceWithPersistentID(device.type(), device.persistentId).value());
+}
 
-    auto map = deviceMap();
-    auto it = map.find(id);
-    if (it != map.end() && it->value.type == type) {
-        auto device = CaptureDevice(it->value.id, it->value.type, it->value.name);
-        device.setEnabled(true);
-        return WTFMove(device);
+void MockRealtimeMediaSource::resetDevices()
+{
+    setDevices(defaultDevices());
+}
+
+void MockRealtimeMediaSource::setDevices(Vector<MockMediaDevice>&& newMockDevices)
+{
+    audioDevices().clear();
+    videoDevices().clear();
+    displayDevices().clear();
+
+    auto& mockDevices = devices();
+    mockDevices = WTFMove(newMockDevices);
+
+    auto& map = deviceMap();
+    map.clear();
+
+    for (const auto& device : mockDevices) {
+        map.add(device.persistentId, device);
+        createCaptureDevice(device);
     }
+}
 
-    return std::nullopt;
+void MockRealtimeMediaSource::addDevice(const MockMediaDevice& device)
+{
+    devices().append(device);
+    deviceMap().set(device.persistentId, device);
+    createCaptureDevice(device);
 }
 
-Vector<CaptureDevice>& MockRealtimeMediaSource::audioDevices()
+void MockRealtimeMediaSource::removeDevice(const String& persistentId)
 {
-    static auto info = makeNeverDestroyed([] {
-        Vector<CaptureDevice> vector;
+    auto& map = deviceMap();
+    auto iterator = map.find(persistentId);
+    if (iterator == map.end())
+        return;
 
-        auto captureDevice = captureDeviceWithPersistentID(CaptureDevice::DeviceType::Microphone, "239c24b0-2b15-11e3-8224-0800200c9a66"_s);
-        ASSERT(captureDevice);
-        vector.append(WTFMove(captureDevice.value()));
+    devices().removeFirstMatching([&persistentId](const auto& device) {
+        return device.persistentId == persistentId;
+    });
 
-        captureDevice = captureDeviceWithPersistentID(CaptureDevice::DeviceType::Microphone, "239c24b1-2b15-11e3-8224-0800200c9a66"_s);
-        ASSERT(captureDevice);
-        vector.append(WTFMove(captureDevice.value()));
+    deviceListForDevice(iterator->value).removeFirstMatching([&persistentId](const auto& device) {
+        return device.persistentId() == persistentId;
+    });
 
-        return vector;
-    }());
-    return info;
+    map.remove(iterator);
 }
 
-Vector<CaptureDevice>& MockRealtimeMediaSource::videoDevices()
+std::optional<CaptureDevice> MockRealtimeMediaSource::captureDeviceWithPersistentID(CaptureDevice::DeviceType type, const String& id)
 {
-    static auto info = makeNeverDestroyed([] {
-        Vector<CaptureDevice> vector;
+    ASSERT(!id.isEmpty());
 
-        auto captureDevice = captureDeviceWithPersistentID(CaptureDevice::DeviceType::Camera, "239c24b2-2b15-11e3-8224-0800200c9a66"_s);
-        ASSERT(captureDevice);
-        vector.append(WTFMove(captureDevice.value()));
+    auto& map = deviceMap();
+    auto iterator = map.find(id);
+    if (iterator == map.end() || iterator->value.type() != type)
+        return std::nullopt;
 
-        captureDevice = captureDeviceWithPersistentID(CaptureDevice::DeviceType::Camera, "239c24b3-2b15-11e3-8224-0800200c9a66"_s);
-        ASSERT(captureDevice);
-        vector.append(WTFMove(captureDevice.value()));
+    CaptureDevice device { iterator->value.persistentId, type, iterator->value.label };
+    device.setEnabled(true);
+    return WTFMove(device);
+}
 
-        return vector;
+Vector<CaptureDevice>& MockRealtimeMediaSource::audioDevices()
+{
+    static auto audioDevices = makeNeverDestroyed([] {
+        Vector<CaptureDevice> audioDevices;
+        for (const auto& device : devices()) {
+            if (device.type() == CaptureDevice::DeviceType::Microphone)
+                audioDevices.append(captureDeviceWithPersistentID(CaptureDevice::DeviceType::Microphone, device.persistentId).value());
+        }
+        return audioDevices;
     }());
-    return info;
+    return audioDevices;
 }
 
+Vector<CaptureDevice>& MockRealtimeMediaSource::videoDevices()
+{
+    static auto videoDevices = makeNeverDestroyed([] {
+        Vector<CaptureDevice> videoDevices;
+        for (const auto& device : devices()) {
+            if (device.type() == CaptureDevice::DeviceType::Camera)
+                videoDevices.append(captureDeviceWithPersistentID(CaptureDevice::DeviceType::Camera, device.persistentId).value());
+        }
+        return videoDevices;
+    }());
+    return videoDevices;
+}
+
 Vector<CaptureDevice>& MockRealtimeMediaSource::displayDevices()
 {
-    static auto devices = makeNeverDestroyed([] {
-        Vector<CaptureDevice> vector;
-
-        auto captureDevice = captureDeviceWithPersistentID(CaptureDevice::DeviceType::Screen, "SCREEN-1"_s);
-        ASSERT(captureDevice);
-        vector.append(WTFMove(captureDevice.value()));
-
-        captureDevice = captureDeviceWithPersistentID(CaptureDevice::DeviceType::Screen, "SCREEN-2"_s);
-        ASSERT(captureDevice);
-        vector.append(WTFMove(captureDevice.value()));
-
-        return vector;
+    static auto displayDevices = makeNeverDestroyed([] {
+        Vector<CaptureDevice> displayDevices;
+        for (const auto& device : devices()) {
+            if (device.type() == CaptureDevice::DeviceType::Screen)
+                displayDevices.append(captureDeviceWithPersistentID(CaptureDevice::DeviceType::Screen, device.persistentId).value());
+        }
+        return displayDevices;
     }());
 
-    return devices;
+    return displayDevices;
 }
 
 MockRealtimeMediaSource::MockRealtimeMediaSource(const String& id, RealtimeMediaSource::Type type, const String& name)
     : RealtimeMediaSource(id, type, name)
+    , m_device(deviceMap().get(id))
 {
     ASSERT(type != RealtimeMediaSource::Type::None);
-
-    auto map = deviceMap();
-    auto it = map.find(id);
-    ASSERT(it != map.end());
-
-    m_device = it->value.device;
     setPersistentID(String(id));
 }
 

Modified: trunk/Source/WebCore/platform/mock/MockRealtimeMediaSource.h (233161 => 233162)


--- trunk/Source/WebCore/platform/mock/MockRealtimeMediaSource.h	2018-06-25 18:53:34 UTC (rev 233161)
+++ trunk/Source/WebCore/platform/mock/MockRealtimeMediaSource.h	2018-06-25 19:19:06 UTC (rev 233162)
@@ -32,16 +32,21 @@
 
 #if ENABLE(MEDIA_STREAM)
 
+#include "CaptureDevice.h"
+#include "MockMediaDevice.h"
 #include "RealtimeMediaSource.h"
 
 namespace WebCore {
 
-class CaptureDevice;
-
 class MockRealtimeMediaSource : public RealtimeMediaSource {
 public:
     virtual ~MockRealtimeMediaSource() = default;
 
+    static void setDevices(Vector<MockMediaDevice>&&);
+    static void addDevice(const MockMediaDevice&);
+    static void removeDevice(const String& persistentId);
+    WEBCORE_EXPORT static void resetDevices();
+
     static Vector<CaptureDevice>& audioDevices();
     static Vector<CaptureDevice>& videoDevices();
     static Vector<CaptureDevice>& displayDevices();
@@ -48,11 +53,11 @@
 
     static std::optional<CaptureDevice> captureDeviceWithPersistentID(CaptureDevice::DeviceType, const String&);
 
-    enum class MockDevice { Invalid, Microphone1, Microphone2, Camera1, Camera2, Screen1, Screen2 };
-
 protected:
     MockRealtimeMediaSource(const String& id, Type, const String& name);
 
+    static void createCaptureDevice(const MockMediaDevice&);
+
     virtual void updateSettings(RealtimeMediaSourceSettings&) = 0;
     virtual void initializeCapabilities(RealtimeMediaSourceCapabilities&) = 0;
     virtual void initializeSupportedConstraints(RealtimeMediaSourceSupportedConstraints&) = 0;
@@ -62,8 +67,8 @@
 
     RealtimeMediaSourceSupportedConstraints& supportedConstraints();
 
-    MockDevice device() const { return m_device; }
-    MockDevice m_device { MockDevice::Invalid };
+    const MockMediaDevice& device() const { return m_device; }
+    MockMediaDevice m_device;
 
 private:
     void initializeCapabilities();

Modified: trunk/Source/WebCore/platform/mock/MockRealtimeMediaSourceCenter.cpp (233161 => 233162)


--- trunk/Source/WebCore/platform/mock/MockRealtimeMediaSourceCenter.cpp	2018-06-25 18:53:34 UTC (rev 233161)
+++ trunk/Source/WebCore/platform/mock/MockRealtimeMediaSourceCenter.cpp	2018-06-25 19:19:06 UTC (rev 233162)
@@ -37,16 +37,39 @@
 
 namespace WebCore {
 
+MockRealtimeMediaSourceCenter& MockRealtimeMediaSourceCenter::singleton()
+{
+    static NeverDestroyed<MockRealtimeMediaSourceCenter> center;
+    return center;
+}
+
 void MockRealtimeMediaSourceCenter::setMockRealtimeMediaSourceCenterEnabled(bool enabled)
 {
-    static NeverDestroyed<MockRealtimeMediaSourceCenter> center;
     static bool active = false;
     if (active != enabled) {
         active = enabled;
-        RealtimeMediaSourceCenter::setSharedStreamCenterOverride(enabled ? &center.get() : nullptr);
+        RealtimeMediaSourceCenter::setSharedStreamCenterOverride(enabled ? &singleton() : nullptr);
     }
 }
 
+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
 
 #endif // ENABLE(MEDIA_STREAM)

Modified: trunk/Source/WebCore/platform/mock/MockRealtimeMediaSourceCenter.h (233161 => 233162)


--- trunk/Source/WebCore/platform/mock/MockRealtimeMediaSourceCenter.h	2018-06-25 18:53:34 UTC (rev 233161)
+++ trunk/Source/WebCore/platform/mock/MockRealtimeMediaSourceCenter.h	2018-06-25 19:19:06 UTC (rev 233162)
@@ -39,6 +39,10 @@
 public:
     WEBCORE_EXPORT static void setMockRealtimeMediaSourceCenterEnabled(bool);
 
+    WEBCORE_EXPORT static void setDevices(Vector<MockMediaDevice>&&);
+    WEBCORE_EXPORT static void addDevice(const MockMediaDevice&);
+    WEBCORE_EXPORT static void removeDevice(const String& persistentId);
+
     static RealtimeMediaSource::VideoCaptureFactory& videoCaptureSourceFactory() { return MockRealtimeVideoSource::factory(); }
     static RealtimeMediaSource::AudioCaptureFactory& audioCaptureSourceFactory() { return MockRealtimeAudioSource::factory(); }
 
@@ -46,6 +50,8 @@
     MockRealtimeMediaSourceCenter() = default;
     friend NeverDestroyed<MockRealtimeMediaSourceCenter>;
 
+    static MockRealtimeMediaSourceCenter& singleton();
+
     RealtimeMediaSource::AudioCaptureFactory& audioFactory() final { return MockRealtimeAudioSource::factory(); }
     RealtimeMediaSource::VideoCaptureFactory& videoFactory() final { return MockRealtimeVideoSource::factory(); }
 

Modified: trunk/Source/WebCore/platform/mock/MockRealtimeVideoSource.cpp (233161 => 233162)


--- trunk/Source/WebCore/platform/mock/MockRealtimeVideoSource.cpp	2018-06-25 18:53:34 UTC (rev 233161)
+++ trunk/Source/WebCore/platform/mock/MockRealtimeVideoSource.cpp	2018-06-25 19:19:06 UTC (rev 233162)
@@ -108,31 +108,18 @@
     : MockRealtimeMediaSource(deviceID, RealtimeMediaSource::Type::Video, name)
     , m_timer(RunLoop::current(), this, &MockRealtimeVideoSource::generateFrame)
 {
-    switch (device()) {
-    case MockDevice::Camera1:
-        setFrameRate(30);
-        setFacingMode(RealtimeMediaSourceSettings::User);
-        break;
-    case MockDevice::Camera2:
-        setFrameRate(15);
-        setFacingMode(RealtimeMediaSourceSettings::Environment);
-        break;
-    case MockDevice::Screen1:
-        setFrameRate(30);
-        break;
-    case MockDevice::Screen2:
-        setFrameRate(10);
-        break;
-    case MockDevice::Microphone1:
-    case MockDevice::Microphone2:
-    case MockDevice::Invalid:
-        ASSERT_NOT_REACHED();
-        break;
-    }
-
     m_dashWidths.reserveInitialCapacity(2);
     m_dashWidths.uncheckedAppend(6);
     m_dashWidths.uncheckedAppend(6);
+
+    if (mockScreen()) {
+        setFrameRate(WTF::get<MockDisplayProperties>(device().properties).defaultFrameRate);
+        return;
+    }
+
+    auto& properties = WTF::get<MockCameraProperties>(device().properties);
+    setFrameRate(properties.defaultFrameRate);
+    setFacingMode(properties.facingModeCapability);
 }
 
 MockRealtimeVideoSource::~MockRealtimeVideoSource()
@@ -191,10 +178,7 @@
 void MockRealtimeVideoSource::initializeCapabilities(RealtimeMediaSourceCapabilities& capabilities)
 {
     if (mockCamera()) {
-        if (device() == MockDevice::Camera1)
-            capabilities.addFacingMode(RealtimeMediaSourceSettings::User);
-        else
-            capabilities.addFacingMode(RealtimeMediaSourceSettings::Environment);
+        capabilities.addFacingMode(WTF::get<MockCameraProperties>(device().properties).facingModeCapability);
 
         capabilities.setWidth(CapabilityValueOrRange(320, 1920));
         capabilities.setHeight(CapabilityValueOrRange(240, 1080));
@@ -392,7 +376,7 @@
         context.drawText(statsFont, TextRun((StringView(string))), statsLocation);
     } else {
         statsLocation.move(0, m_statsFontSize);
-        context.drawText(statsFont, TextRun((StringView(device() == MockDevice::Screen1 ? "Screen 1" : "Screen 2"))), statsLocation);
+        context.drawText(statsFont, TextRun { id() }, statsLocation);
     }
 
     FloatPoint bipBopLocation(size.width() * .6, size.height() * .6);
@@ -431,27 +415,7 @@
     auto& size = this->size();
     FloatRect frameRect(FloatPoint(), size);
 
-    Color fillColor;
-    switch (device()) {
-    case MockDevice::Camera1:
-        fillColor = Color::black;
-        break;
-    case MockDevice::Camera2:
-        fillColor = Color::darkGray;
-        break;
-    case MockDevice::Screen1:
-        fillColor = Color::lightGray;
-        break;
-    case MockDevice::Screen2:
-        fillColor = Color::yellow;
-        break;
-    case MockDevice::Microphone1:
-    case MockDevice::Microphone2:
-    case MockDevice::Invalid:
-        ASSERT_NOT_REACHED();
-        break;
-    }
-
+    auto fillColor = mockCamera() ? WTF::get<MockCameraProperties>(device().properties).fillColor : WTF::get<MockDisplayProperties>(device().properties).fillColor;
     context.fillRect(FloatRect(FloatPoint(), size), fillColor);
 
     if (!muted()) {

Modified: trunk/Source/WebCore/platform/mock/MockRealtimeVideoSource.h (233161 => 233162)


--- trunk/Source/WebCore/platform/mock/MockRealtimeVideoSource.h	2018-06-25 18:53:34 UTC (rev 233161)
+++ trunk/Source/WebCore/platform/mock/MockRealtimeVideoSource.h	2018-06-25 19:19:06 UTC (rev 233162)
@@ -83,8 +83,8 @@
 
     void delaySamples(Seconds) override;
 
-    bool mockCamera() const { return device() == MockDevice::Camera1 || device() == MockDevice::Camera2; }
-    bool mockScreen() const { return device() == MockDevice::Screen1 || device() == MockDevice::Screen2; }
+    bool mockCamera() const { return WTF::holds_alternative<MockCameraProperties>(device().properties); }
+    bool mockScreen() const { return WTF::holds_alternative<MockDisplayProperties>(device().properties); }
 
     float m_baseFontSize { 0 };
     float m_bipBopFontSize { 0 };

Modified: trunk/Source/WebKit/CMakeLists.txt (233161 => 233162)


--- trunk/Source/WebKit/CMakeLists.txt	2018-06-25 18:53:34 UTC (rev 233161)
+++ trunk/Source/WebKit/CMakeLists.txt	2018-06-25 19:19:06 UTC (rev 233162)
@@ -402,6 +402,7 @@
     UIProcess/API/C/WKInspector.cpp
     UIProcess/API/C/WKKeyValueStorageManager.cpp
     UIProcess/API/C/WKMediaSessionMetadata.cpp
+    UIProcess/API/C/WKMockMediaDevice.cpp
     UIProcess/API/C/WKNavigationActionRef.cpp
     UIProcess/API/C/WKNavigationDataRef.cpp
     UIProcess/API/C/WKNavigationRef.cpp

Modified: trunk/Source/WebKit/ChangeLog (233161 => 233162)


--- trunk/Source/WebKit/ChangeLog	2018-06-25 18:53:34 UTC (rev 233161)
+++ trunk/Source/WebKit/ChangeLog	2018-06-25 19:19:06 UTC (rev 233162)
@@ -1,3 +1,36 @@
+2018-06-25  Youenn Fablet  <you...@apple.com>
+
+        Add API to control mock media devices
+        https://bugs.webkit.org/show_bug.cgi?id=186958
+
+        Reviewed by Eric Carlson.
+
+        Add API to clear, set, remove and reset mock media devices.
+        The mock media center of UIProcess and all WebProcesses are updated.
+
+        * CMakeLists.txt:
+        * UIProcess/API/C/WKMockMediaDevice.cpp: Added.
+        (typeFromString):
+        (WKAddMockMediaDevice):
+        (WKClearMockMediaDevices):
+        (WKRemoveMockMediaDevice):
+        (WKResetMockMediaDevices):
+        * UIProcess/API/C/WKMockMediaDevice.h: Added.
+        * UIProcess/WebProcessPool.cpp:
+        (WebKit::WebProcessPool::addMockMediaDevice):
+        (WebKit::WebProcessPool::clearMockMediaDevices):
+        (WebKit::WebProcessPool::removeMockMediaDevice):
+        (WebKit::WebProcessPool::resetMockMediaDevices):
+        * UIProcess/WebProcessPool.h:
+        * WebKit.xcodeproj/project.pbxproj:
+        * WebProcess/WebProcess.cpp:
+        (WebKit::WebProcess::addMockMediaDevice):
+        (WebKit::WebProcess::clearMockMediaDevices):
+        (WebKit::WebProcess::removeMockMediaDevice):
+        (WebKit::WebProcess::resetMockMediaDevices):
+        * WebProcess/WebProcess.h:
+        * WebProcess/WebProcess.messages.in:
+
 2018-06-25  Wenson Hsieh  <wenson_hs...@apple.com>
 
         [iPad apps on macOS] Click events are broken in WKWebView

Added: trunk/Source/WebKit/UIProcess/API/C/WKMockMediaDevice.cpp (0 => 233162)


--- trunk/Source/WebKit/UIProcess/API/C/WKMockMediaDevice.cpp	                        (rev 0)
+++ trunk/Source/WebKit/UIProcess/API/C/WKMockMediaDevice.cpp	2018-06-25 19:19:06 UTC (rev 233162)
@@ -0,0 +1,66 @@
+/*
+ * Copyright (C) 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
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE, INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#include "config.h"
+#include "WKMockMediaDevice.h"
+
+#include "WKAPICast.h"
+#include "WKString.h"
+#include "WebProcessPool.h"
+#include <WebCore/MockMediaDevice.h>
+
+using namespace WebKit;
+
+void WKAddMockMediaDevice(WKContextRef context, WKStringRef persistentId, WKStringRef label, WKStringRef type)
+{
+#if ENABLE(MEDIA_STREAM)
+    String typeString = WebKit::toImpl(type)->string();
+    Variant<WebCore::MockMicrophoneProperties, WebCore::MockCameraProperties, WebCore::MockDisplayProperties> properties;
+    if (typeString == "camera")
+        properties = WebCore::MockCameraProperties { };
+    else if (typeString == "screen")
+        properties = WebCore::MockDisplayProperties { };
+    else if (typeString != "microphone")
+        return;
+
+    toImpl(context)->addMockMediaDevice({ WebKit::toImpl(persistentId)->string(), WebKit::toImpl(label)->string(), WTFMove(properties) });
+#endif
+}
+
+void WKClearMockMediaDevices(WKContextRef context)
+{
+    toImpl(context)->clearMockMediaDevices();
+}
+
+void WKRemoveMockMediaDevice(WKContextRef context, WKStringRef persistentId)
+{
+    toImpl(context)->removeMockMediaDevice(WebKit::toImpl(persistentId)->string());
+}
+
+void WKResetMockMediaDevices(WKContextRef context)
+{
+    toImpl(context)->resetMockMediaDevices();
+}

Copied: trunk/Source/WebKit/UIProcess/API/C/WKMockMediaDevice.h (from rev 233161, trunk/Source/WebCore/platform/mock/MockRealtimeMediaSourceCenter.cpp) (0 => 233162)


--- trunk/Source/WebKit/UIProcess/API/C/WKMockMediaDevice.h	                        (rev 0)
+++ trunk/Source/WebKit/UIProcess/API/C/WKMockMediaDevice.h	2018-06-25 19:19:06 UTC (rev 233162)
@@ -0,0 +1,42 @@
+/*
+ * Copyright (C) 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
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE, INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#pragma once
+
+#include <WebKit/WKBase.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+WK_EXPORT void WKAddMockMediaDevice(WKContextRef, WKStringRef persistentId, WKStringRef label, WKStringRef type);
+WK_EXPORT void WKClearMockMediaDevices(WKContextRef);
+WK_EXPORT void WKRemoveMockMediaDevice(WKContextRef, WKStringRef persistentId);
+WK_EXPORT void WKResetMockMediaDevices(WKContextRef);
+
+#ifdef __cplusplus
+}
+#endif

Modified: trunk/Source/WebKit/UIProcess/WebProcessPool.cpp (233161 => 233162)


--- trunk/Source/WebKit/UIProcess/WebProcessPool.cpp	2018-06-25 18:53:34 UTC (rev 233161)
+++ trunk/Source/WebKit/UIProcess/WebProcessPool.cpp	2018-06-25 19:19:06 UTC (rev 233162)
@@ -82,6 +82,7 @@
 #include <_javascript_Core/JSCInlines.h>
 #include <WebCore/ApplicationCacheStorage.h>
 #include <WebCore/LogInitialization.h>
+#include <WebCore/MockRealtimeMediaSourceCenter.h>
 #include <WebCore/NetworkStorageSession.h>
 #include <WebCore/PlatformScreen.h>
 #include <WebCore/Process.h>
@@ -2212,4 +2213,36 @@
         m_suspendedPages.remove(iterator);
 }
 
+void WebProcessPool::addMockMediaDevice(const MockMediaDevice& device)
+{
+#if ENABLE(MEDIA_STREAM)
+    MockRealtimeMediaSourceCenter::addDevice(device);
+    sendToAllProcesses(Messages::WebProcess::AddMockMediaDevice { device });
+#endif
+}
+
+void WebProcessPool::clearMockMediaDevices()
+{
+#if ENABLE(MEDIA_STREAM)
+    MockRealtimeMediaSourceCenter::setDevices({ });
+    sendToAllProcesses(Messages::WebProcess::ClearMockMediaDevices { });
+#endif
+}
+
+void WebProcessPool::removeMockMediaDevice(const String& persistentId)
+{
+#if ENABLE(MEDIA_STREAM)
+    MockRealtimeMediaSourceCenter::removeDevice(persistentId);
+    sendToAllProcesses(Messages::WebProcess::RemoveMockMediaDevice { persistentId });
+#endif
+}
+
+void WebProcessPool::resetMockMediaDevices()
+{
+#if ENABLE(MEDIA_STREAM)
+    MockRealtimeMediaSource::resetDevices();
+    sendToAllProcesses(Messages::WebProcess::ResetMockMediaDevices { });
+#endif
+}
+
 } // namespace WebKit

Modified: trunk/Source/WebKit/UIProcess/WebProcessPool.h (233161 => 233162)


--- trunk/Source/WebKit/UIProcess/WebProcessPool.h	2018-06-25 18:53:34 UTC (rev 233161)
+++ trunk/Source/WebKit/UIProcess/WebProcessPool.h	2018-06-25 19:19:06 UTC (rev 233162)
@@ -82,6 +82,10 @@
 class PageConfiguration;
 }
 
+namespace WebCore {
+struct MockMediaDevice;
+}
+
 namespace WebKit {
 
 class DownloadProxy;
@@ -454,6 +458,11 @@
 
     void screenPropertiesStateChanged();
 
+    void addMockMediaDevice(const WebCore::MockMediaDevice&);
+    void clearMockMediaDevices();
+    void removeMockMediaDevice(const String& persistentId);
+    void resetMockMediaDevices();
+
 private:
     void platformInitialize();
 

Modified: trunk/Source/WebKit/WebKit.xcodeproj/project.pbxproj (233161 => 233162)


--- trunk/Source/WebKit/WebKit.xcodeproj/project.pbxproj	2018-06-25 18:53:34 UTC (rev 233161)
+++ trunk/Source/WebKit/WebKit.xcodeproj/project.pbxproj	2018-06-25 19:19:06 UTC (rev 233162)
@@ -913,6 +913,8 @@
 		410482CE1DDD324F00F006D0 /* RTCNetwork.h in Headers */ = {isa = PBXBuildFile; fileRef = 410482CC1DDD2FB500F006D0 /* RTCNetwork.h */; };
 		4112B5551FA0EA7A00E67875 /* NetworkRTCResolver.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4112B5471F9FD3AB00E67875 /* NetworkRTCResolver.cpp */; };
 		4112B5551FA0EA7A00E67986 /* NetworkRTCResolverCocoa.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4112B5471F9FD3AB00E67986 /* NetworkRTCResolverCocoa.cpp */; };
+		411A8DDB20DDD1AC0060D34F /* WKMockMediaDevice.h in Headers */ = {isa = PBXBuildFile; fileRef = 411A8DD920DDB6050060D34F /* WKMockMediaDevice.h */; settings = {ATTRIBUTES = (Private, ); }; };
+		411A8DDC20DDD23F0060D34F /* WKMockMediaDevice.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 411A8DDA20DDB6050060D34F /* WKMockMediaDevice.cpp */; };
 		411B22641E371BA6004F7363 /* LibWebRTCNetwork.h in Headers */ = {isa = PBXBuildFile; fileRef = 411B22621E371244004F7363 /* LibWebRTCNetwork.h */; };
 		413075A91DE85F2C0039EC69 /* NetworkRTCSocket.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 413075981DE84FB00039EC69 /* NetworkRTCSocket.cpp */; };
 		413075AA1DE85F300039EC69 /* NetworkRTCMonitor.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4130759A1DE84FB00039EC69 /* NetworkRTCMonitor.cpp */; };
@@ -3299,6 +3301,8 @@
 		4112B5471F9FD3AB00E67986 /* NetworkRTCResolverCocoa.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = NetworkRTCResolverCocoa.cpp; path = NetworkProcess/webrtc/NetworkRTCResolverCocoa.cpp; sourceTree = "<group>"; };
 		4112B5481F9FD3AC00E67875 /* NetworkRTCResolver.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = NetworkRTCResolver.h; path = NetworkProcess/webrtc/NetworkRTCResolver.h; sourceTree = "<group>"; };
 		4112B5481F9FD3AC00E67986 /* NetworkRTCResolverCocoa.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = NetworkRTCResolverCocoa.h; path = NetworkProcess/webrtc/NetworkRTCResolverCocoa.h; sourceTree = "<group>"; };
+		411A8DD920DDB6050060D34F /* WKMockMediaDevice.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = WKMockMediaDevice.h; sourceTree = "<group>"; };
+		411A8DDA20DDB6050060D34F /* WKMockMediaDevice.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = WKMockMediaDevice.cpp; sourceTree = "<group>"; };
 		411B22621E371244004F7363 /* LibWebRTCNetwork.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = LibWebRTCNetwork.h; path = Network/webrtc/LibWebRTCNetwork.h; sourceTree = "<group>"; };
 		413075981DE84FB00039EC69 /* NetworkRTCSocket.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = NetworkRTCSocket.cpp; path = NetworkProcess/webrtc/NetworkRTCSocket.cpp; sourceTree = "<group>"; };
 		413075991DE84FB00039EC69 /* NetworkRTCSocket.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = NetworkRTCSocket.h; path = NetworkProcess/webrtc/NetworkRTCSocket.h; sourceTree = "<group>"; };
@@ -7572,6 +7576,8 @@
 				C98C48A81B6FD5B500145103 /* WKMediaSessionFocusManager.h */,
 				C9CD43991B4B024200239E33 /* WKMediaSessionMetadata.cpp */,
 				C9CD439A1B4B024200239E33 /* WKMediaSessionMetadata.h */,
+				411A8DDA20DDB6050060D34F /* WKMockMediaDevice.cpp */,
+				411A8DD920DDB6050060D34F /* WKMockMediaDevice.h */,
 				C09AE5E8125257C20025825D /* WKNativeEvent.h */,
 				2D3A65D81A7C3A1F00CAC637 /* WKNavigationActionRef.cpp */,
 				2D3A65D91A7C3A1F00CAC637 /* WKNavigationActionRef.h */,
@@ -9643,6 +9649,7 @@
 				C98C48AA1B6FD5B500145103 /* WKMediaSessionFocusManager.h in Headers */,
 				C9CD439D1B4B024F00239E33 /* WKMediaSessionMetadata.h in Headers */,
 				1AB40EE61BF677E300BA81BE /* WKMenuItemIdentifiersPrivate.h in Headers */,
+				411A8DDB20DDD1AC0060D34F /* WKMockMediaDevice.h in Headers */,
 				BC4075FE124FF0270068F20A /* WKMutableArray.h in Headers */,
 				BC407600124FF0270068F20A /* WKMutableDictionary.h in Headers */,
 				C09AE5E9125257C20025825D /* WKNativeEvent.h in Headers */,
@@ -10358,13 +10365,9 @@
 			buildActionMask = 2147483647;
 			files = (
 			);
-			inputFileListPaths = (
-			);
 			inputPaths = (
 			);
 			name = "Unlock keychain";
-			outputFileListPaths = (
-			);
 			outputPaths = (
 			);
 			runOnlyForDeploymentPostprocessing = 0;
@@ -10376,13 +10379,9 @@
 			buildActionMask = 2147483647;
 			files = (
 			);
-			inputFileListPaths = (
-			);
 			inputPaths = (
 			);
 			name = "Unlock keychain";
-			outputFileListPaths = (
-			);
 			outputPaths = (
 			);
 			runOnlyForDeploymentPostprocessing = 0;
@@ -10394,13 +10393,9 @@
 			buildActionMask = 2147483647;
 			files = (
 			);
-			inputFileListPaths = (
-			);
 			inputPaths = (
 			);
 			name = "Remove stale entitlement file";
-			outputFileListPaths = (
-			);
 			outputPaths = (
 			);
 			runOnlyForDeploymentPostprocessing = 0;
@@ -10412,13 +10407,9 @@
 			buildActionMask = 2147483647;
 			files = (
 			);
-			inputFileListPaths = (
-			);
 			inputPaths = (
 			);
 			name = "Remove stale entitlement file";
-			outputFileListPaths = (
-			);
 			outputPaths = (
 			);
 			runOnlyForDeploymentPostprocessing = 0;
@@ -10430,14 +10421,10 @@
 			buildActionMask = 2147483647;
 			files = (
 			);
-			inputFileListPaths = (
-			);
 			inputPaths = (
 				"$(TEMP_FILE_DIR)/$(FULL_PRODUCT_NAME).xcent",
 			);
 			name = "Process WebContent entitlements";
-			outputFileListPaths = (
-			);
 			outputPaths = (
 			);
 			runOnlyForDeploymentPostprocessing = 0;
@@ -10449,14 +10436,10 @@
 			buildActionMask = 2147483647;
 			files = (
 			);
-			inputFileListPaths = (
-			);
 			inputPaths = (
 				"$(TEMP_FILE_DIR)/$(FULL_PRODUCT_NAME).xcent",
 			);
 			name = "Process WebContent entitlements";
-			outputFileListPaths = (
-			);
 			outputPaths = (
 			);
 			runOnlyForDeploymentPostprocessing = 0;
@@ -11465,6 +11448,7 @@
 				C98C48A91B6FD5B500145103 /* WKMediaSessionFocusManager.cpp in Sources */,
 				C9CD439E1B4B025300239E33 /* WKMediaSessionMetadata.cpp in Sources */,
 				1AB40EE51BF677E300BA81BE /* WKMenuItemIdentifiers.mm in Sources */,
+				411A8DDC20DDD23F0060D34F /* WKMockMediaDevice.cpp in Sources */,
 				BC4075FD124FF0270068F20A /* WKMutableArray.cpp in Sources */,
 				BC4075FF124FF0270068F20A /* WKMutableDictionary.cpp in Sources */,
 				1A5B1C501898606F004FCF9B /* WKNavigation.mm in Sources */,

Modified: trunk/Source/WebKit/WebProcess/WebProcess.cpp (233161 => 233162)


--- trunk/Source/WebKit/WebProcess/WebProcess.cpp	2018-06-25 18:53:34 UTC (rev 233161)
+++ trunk/Source/WebKit/WebProcess/WebProcess.cpp	2018-06-25 19:19:06 UTC (rev 233162)
@@ -101,6 +101,7 @@
 #include <WebCore/MemoryCache.h>
 #include <WebCore/MemoryRelease.h>
 #include <WebCore/MessagePort.h>
+#include <WebCore/MockRealtimeMediaSourceCenter.h>
 #include <WebCore/NetworkStorageSession.h>
 #include <WebCore/Page.h>
 #include <WebCore/PageCache.h>
@@ -1690,4 +1691,26 @@
 }
 #endif
 
+#if ENABLE(MEDIA_STREAM)
+void WebProcess::addMockMediaDevice(const WebCore::MockMediaDevice& device)
+{
+    MockRealtimeMediaSourceCenter::addDevice(device);
+}
+
+void WebProcess::clearMockMediaDevices()
+{
+    MockRealtimeMediaSourceCenter::setDevices({ });
+}
+
+void WebProcess::removeMockMediaDevice(const String& persistentId)
+{
+    MockRealtimeMediaSourceCenter::removeDevice(persistentId);
+}
+
+void WebProcess::resetMockMediaDevices()
+{
+    MockRealtimeMediaSource::resetDevices();
+}
+#endif
+
 } // namespace WebKit

Modified: trunk/Source/WebKit/WebProcess/WebProcess.h (233161 => 233162)


--- trunk/Source/WebKit/WebProcess/WebProcess.h	2018-06-25 18:53:34 UTC (rev 233161)
+++ trunk/Source/WebKit/WebProcess/WebProcess.h	2018-06-25 19:19:06 UTC (rev 233162)
@@ -69,6 +69,7 @@
 class UserGestureToken;
 struct MessagePortIdentifier;
 struct MessageWithMessagePorts;
+struct MockMediaDevice;
 struct PluginInfo;
 struct SecurityOriginData;
 struct SoupNetworkProxySettings;
@@ -359,6 +360,13 @@
     void stopRunLoop() override;
 #endif
 
+#if ENABLE(MEDIA_STREAM)
+    void addMockMediaDevice(const WebCore::MockMediaDevice&);
+    void clearMockMediaDevices();
+    void removeMockMediaDevice(const String& persistentId);
+    void resetMockMediaDevices();
+#endif
+
     void platformInitializeProcess(const ChildProcessInitializationParameters&);
 
     // IPC::Connection::Client

Modified: trunk/Source/WebKit/WebProcess/WebProcess.messages.in (233161 => 233162)


--- trunk/Source/WebKit/WebProcess/WebProcess.messages.in	2018-06-25 18:53:34 UTC (rev 233161)
+++ trunk/Source/WebKit/WebProcess/WebProcess.messages.in	2018-06-25 19:19:06 UTC (rev 233162)
@@ -139,4 +139,11 @@
 #if PLATFORM(COCOA)
     SetMediaMIMETypes(Vector<String> types)
 #endif
+
+#if ENABLE(MEDIA_STREAM)
+    AddMockMediaDevice(struct WebCore::MockMediaDevice device);
+    ClearMockMediaDevices();
+    RemoveMockMediaDevice(String persistentId);
+    ResetMockMediaDevices();
+#endif
 }

Modified: trunk/Tools/ChangeLog (233161 => 233162)


--- trunk/Tools/ChangeLog	2018-06-25 18:53:34 UTC (rev 233161)
+++ trunk/Tools/ChangeLog	2018-06-25 19:19:06 UTC (rev 233162)
@@ -1,3 +1,31 @@
+2018-06-25  Youenn Fablet  <you...@apple.com>
+
+        Add API to control mock media devices
+        https://bugs.webkit.org/show_bug.cgi?id=186958
+
+        Reviewed by Eric Carlson.
+
+        Add test runner API to clear/add/remove/reset mock media devices.
+
+        * WebKitTestRunner/InjectedBundle/Bindings/TestRunner.idl:
+        * WebKitTestRunner/InjectedBundle/TestRunner.cpp:
+        (WTR::TestRunner::addMockMediaDevice):
+        (WTR::TestRunner::addMockCameraDevice):
+        (WTR::TestRunner::addMockMicrophoneDevice):
+        (WTR::TestRunner::addMockScreenDevice):
+        (WTR::TestRunner::clearMockMediaDevices):
+        (WTR::TestRunner::removeMockMediaDevice):
+        (WTR::TestRunner::resetMockMediaDevices):
+        * WebKitTestRunner/InjectedBundle/TestRunner.h:
+        * WebKitTestRunner/TestController.cpp:
+        (WTR::TestController::addMockMediaDevice):
+        (WTR::TestController::clearMockMediaDevices):
+        (WTR::TestController::removeMockMediaDevice):
+        (WTR::TestController::resetMockMediaDevices):
+        * WebKitTestRunner/TestController.h:
+        * WebKitTestRunner/TestInvocation.cpp:
+        (WTR::TestInvocation::didReceiveSynchronousMessageFromInjectedBundle):
+
 2018-06-25  Aakash Jain  <aakash_j...@apple.com>
 
         [ews-build] Add support for try Buildbot try schedulers

Modified: trunk/Tools/WebKitTestRunner/InjectedBundle/Bindings/TestRunner.idl (233161 => 233162)


--- trunk/Tools/WebKitTestRunner/InjectedBundle/Bindings/TestRunner.idl	2018-06-25 18:53:34 UTC (rev 233161)
+++ trunk/Tools/WebKitTestRunner/InjectedBundle/Bindings/TestRunner.idl	2018-06-25 19:19:06 UTC (rev 233162)
@@ -336,4 +336,11 @@
     void getApplicationManifestThen(object callback);
 
     void installFakeHelvetica(DOMString configuration);
+
+    void addMockCameraDevice(DOMString persistentId, DOMString label);
+    void addMockMicrophoneDevice(DOMString persistentId, DOMString label);
+    void addMockScreenDevice(DOMString persistentId, DOMString label);
+    void clearMockMediaDevices();
+    void removeMockMediaDevice(DOMString persistentId);
+    void resetMockMediaDevices();
 };

Modified: trunk/Tools/WebKitTestRunner/InjectedBundle/TestRunner.cpp (233161 => 233162)


--- trunk/Tools/WebKitTestRunner/InjectedBundle/TestRunner.cpp	2018-06-25 18:53:34 UTC (rev 233161)
+++ trunk/Tools/WebKitTestRunner/InjectedBundle/TestRunner.cpp	2018-06-25 19:19:06 UTC (rev 233162)
@@ -1971,6 +1971,71 @@
     callTestRunnerCallback(AllStorageAccessEntriesCallbackID, 1, &result);
 }
 
+void TestRunner::addMockMediaDevice(JSStringRef persistentId, JSStringRef label, const char* type)
+{
+    Vector<WKRetainPtr<WKStringRef>> keys;
+    Vector<WKRetainPtr<WKTypeRef>> values;
+
+    keys.append({ AdoptWK, WKStringCreateWithUTF8CString("PersistentID") });
+    values.append(toWK(persistentId));
+
+    keys.append({ AdoptWK, WKStringCreateWithUTF8CString("Label") });
+    values.append(toWK(label));
+
+    keys.append({ AdoptWK, WKStringCreateWithUTF8CString("Type") });
+    values.append({ AdoptWK, WKStringCreateWithUTF8CString(type) });
+
+    Vector<WKStringRef> rawKeys;
+    Vector<WKTypeRef> rawValues;
+    rawKeys.resize(keys.size());
+    rawValues.resize(values.size());
+
+    for (size_t i = 0; i < keys.size(); ++i) {
+        rawKeys[i] = keys[i].get();
+        rawValues[i] = values[i].get();
+    }
+
+    WKRetainPtr<WKStringRef> messageName(AdoptWK, WKStringCreateWithUTF8CString("AddMockMediaDevice"));
+    WKRetainPtr<WKDictionaryRef> messageBody(AdoptWK, WKDictionaryCreate(rawKeys.data(), rawValues.data(), rawKeys.size()));
+
+    WKBundlePostSynchronousMessage(InjectedBundle::singleton().bundle(), messageName.get(), messageBody.get(), nullptr);
+}
+
+void TestRunner::addMockCameraDevice(JSStringRef persistentId, JSStringRef label)
+{
+    addMockMediaDevice(persistentId, label, "camera");
+}
+
+void TestRunner::addMockMicrophoneDevice(JSStringRef persistentId, JSStringRef label)
+{
+    addMockMediaDevice(persistentId, label, "microphone");
+}
+
+void TestRunner::addMockScreenDevice(JSStringRef persistentId, JSStringRef label)
+{
+    addMockMediaDevice(persistentId, label, "screen");
+}
+
+void TestRunner::clearMockMediaDevices()
+{
+    WKRetainPtr<WKStringRef> messageName(AdoptWK, WKStringCreateWithUTF8CString("ClearMockMediaDevices"));
+    WKBundlePostSynchronousMessage(InjectedBundle::singleton().bundle(), messageName.get(), nullptr, nullptr);
+}
+
+void TestRunner::removeMockMediaDevice(JSStringRef persistentId)
+{
+    WKRetainPtr<WKStringRef> messageName(AdoptWK, WKStringCreateWithUTF8CString("RemoveMockMediaDevice"));
+    WKRetainPtr<WKTypeRef> messageBody(toWK(persistentId));
+
+    WKBundlePostSynchronousMessage(InjectedBundle::singleton().bundle(), messageName.get(), messageBody.get(), nullptr);
+}
+
+void TestRunner::resetMockMediaDevices()
+{
+    WKRetainPtr<WKStringRef> messageName(AdoptWK, WKStringCreateWithUTF8CString("ResetMockMediaDevices"));
+    WKBundlePostSynchronousMessage(InjectedBundle::singleton().bundle(), messageName.get(), nullptr, nullptr);
+}
+
 #if PLATFORM(MAC)
 void TestRunner::connectMockGamepad(unsigned index)
 {

Modified: trunk/Tools/WebKitTestRunner/InjectedBundle/TestRunner.h (233161 => 233162)


--- trunk/Tools/WebKitTestRunner/InjectedBundle/TestRunner.h	2018-06-25 18:53:34 UTC (rev 233161)
+++ trunk/Tools/WebKitTestRunner/InjectedBundle/TestRunner.h	2018-06-25 19:19:06 UTC (rev 233162)
@@ -446,6 +446,13 @@
     void dumpAllHTTPRedirectedResponseHeaders() { m_dumpAllHTTPRedirectedResponseHeaders = true; }
     bool shouldDumpAllHTTPRedirectedResponseHeaders() const { return m_dumpAllHTTPRedirectedResponseHeaders; }
 
+    void addMockCameraDevice(JSStringRef persistentId, JSStringRef label);
+    void addMockMicrophoneDevice(JSStringRef persistentId, JSStringRef label);
+    void addMockScreenDevice(JSStringRef persistentId, JSStringRef label);
+    void clearMockMediaDevices();
+    void removeMockMediaDevice(JSStringRef persistentId);
+    void resetMockMediaDevices();
+
 private:
     TestRunner();
 
@@ -455,6 +462,8 @@
     void setDumpPixels(bool);
     void setWaitUntilDone(bool);
 
+    void addMockMediaDevice(JSStringRef persistentId, JSStringRef label, const char* type);
+
     WKRetainPtr<WKURLRef> m_testURL; // Set by InjectedBundlePage once provisional load starts.
 
     bool m_shouldDumpAllFrameScrollPositions;

Modified: trunk/Tools/WebKitTestRunner/TestController.cpp (233161 => 233162)


--- trunk/Tools/WebKitTestRunner/TestController.cpp	2018-06-25 18:53:34 UTC (rev 233161)
+++ trunk/Tools/WebKitTestRunner/TestController.cpp	2018-06-25 19:19:06 UTC (rev 233162)
@@ -43,6 +43,7 @@
 #include <WebKit/WKFrameHandleRef.h>
 #include <WebKit/WKFrameInfoRef.h>
 #include <WebKit/WKIconDatabase.h>
+#include <WebKit/WKMockMediaDevice.h>
 #include <WebKit/WKNavigationResponseRef.h>
 #include <WebKit/WKNotification.h>
 #include <WebKit/WKNotificationManager.h>
@@ -2866,6 +2867,26 @@
     WKWebsiteDataStoreStatisticsResetToConsistentState(dataStore);
 }
 
+void TestController::addMockMediaDevice(WKStringRef persistentID, WKStringRef label, WKStringRef type)
+{
+    WKAddMockMediaDevice(platformContext(), persistentID, label, type);
+}
+
+void TestController::clearMockMediaDevices()
+{
+    WKClearMockMediaDevices(platformContext());
+}
+
+void TestController::removeMockMediaDevice(WKStringRef persistentID)
+{
+    WKRemoveMockMediaDevice(platformContext(), persistentID);
+}
+
+void TestController::resetMockMediaDevices()
+{
+    WKResetMockMediaDevices(platformContext());
+}
+
 #if !PLATFORM(COCOA)
 void TestController::platformAddTestOptions(TestOptions&) const
 {

Modified: trunk/Tools/WebKitTestRunner/TestController.h (233161 => 233162)


--- trunk/Tools/WebKitTestRunner/TestController.h	2018-06-25 18:53:34 UTC (rev 233161)
+++ trunk/Tools/WebKitTestRunner/TestController.h	2018-06-25 19:19:06 UTC (rev 233162)
@@ -213,6 +213,11 @@
     bool didReceiveServerRedirectForProvisionalNavigation() const { return m_didReceiveServerRedirectForProvisionalNavigation; }
     void clearDidReceiveServerRedirectForProvisionalNavigation() { m_didReceiveServerRedirectForProvisionalNavigation = false; }
 
+    void addMockMediaDevice(WKStringRef persistentID, WKStringRef label, WKStringRef type);
+    void clearMockMediaDevices();
+    void removeMockMediaDevice(WKStringRef persistentID);
+    void resetMockMediaDevices();
+
 private:
     WKRetainPtr<WKPageConfigurationRef> generatePageConfiguration(WKContextConfigurationRef);
     WKRetainPtr<WKContextConfigurationRef> generateContextConfiguration() const;

Modified: trunk/Tools/WebKitTestRunner/TestInvocation.cpp (233161 => 233162)


--- trunk/Tools/WebKitTestRunner/TestInvocation.cpp	2018-06-25 18:53:34 UTC (rev 233161)
+++ trunk/Tools/WebKitTestRunner/TestInvocation.cpp	2018-06-25 19:19:06 UTC (rev 233162)
@@ -916,6 +916,39 @@
         return nullptr;
     }
 
+    if (WKStringIsEqualToUTF8CString(messageName, "AddMockMediaDevice")) {
+        ASSERT(WKGetTypeID(messageBody) == WKDictionaryGetTypeID());
+
+        WKDictionaryRef messageBodyDictionary = static_cast<WKDictionaryRef>(messageBody);
+        WKRetainPtr<WKStringRef> persistentIDKey(AdoptWK, WKStringCreateWithUTF8CString("PersistentID"));
+        WKRetainPtr<WKStringRef> labelKey(AdoptWK, WKStringCreateWithUTF8CString("Label"));
+        WKRetainPtr<WKStringRef> typeKey(AdoptWK, WKStringCreateWithUTF8CString("Type"));
+
+        auto persistentID = static_cast<WKStringRef>(WKDictionaryGetItemForKey(messageBodyDictionary, persistentIDKey.get()));
+        auto label = static_cast<WKStringRef>(WKDictionaryGetItemForKey(messageBodyDictionary, labelKey.get()));
+        auto type = static_cast<WKStringRef>(WKDictionaryGetItemForKey(messageBodyDictionary, typeKey.get()));
+
+        TestController::singleton().addMockMediaDevice(persistentID, label, type);
+        return nullptr;
+    }
+
+    if (WKStringIsEqualToUTF8CString(messageName, "ClearMockMediaDevices")) {
+        TestController::singleton().clearMockMediaDevices();
+        return nullptr;
+    }
+
+    if (WKStringIsEqualToUTF8CString(messageName, "RemoveMockMediaDevice")) {
+        WKStringRef persistentId = static_cast<WKStringRef>(messageBody);
+
+        TestController::singleton().removeMockMediaDevice(persistentId);
+        return nullptr;
+    }
+
+    if (WKStringIsEqualToUTF8CString(messageName, "ResetMockMediaDevices")) {
+        TestController::singleton().resetMockMediaDevices();
+        return nullptr;
+    }
+
 #if PLATFORM(MAC)
     if (WKStringIsEqualToUTF8CString(messageName, "ConnectMockGamepad")) {
         ASSERT(WKGetTypeID(messageBody) == WKUInt64GetTypeID());
_______________________________________________
webkit-changes mailing list
webkit-changes@lists.webkit.org
https://lists.webkit.org/mailman/listinfo/webkit-changes

Reply via email to