WebKit Bugzilla
Attachment 343418 Details for
Bug 186958
: Add API to control mock media devices
Home
|
New
|
Browse
|
Search
|
[?]
|
Reports
|
Requests
|
Help
|
New Account
|
Log In
Remember
[x]
|
Forgot Password
Login:
[x]
[patch]
Patch
bug-186958-20180622213751.patch (text/plain), 69.16 KB, created by
youenn fablet
on 2018-06-22 21:37:52 PDT
(
hide
)
Description:
Patch
Filename:
MIME Type:
Creator:
youenn fablet
Created:
2018-06-22 21:37:52 PDT
Size:
69.16 KB
patch
obsolete
>Subversion Revision: 232956 >diff --git a/Source/WebCore/ChangeLog b/Source/WebCore/ChangeLog >index 15da6f3697cc21f55d291a4727d8d97cfaa44a9d..1a74f96eacf2db188a8da6c862e2f91b0b992ebe 100644 >--- a/Source/WebCore/ChangeLog >+++ b/Source/WebCore/ChangeLog >@@ -1,3 +1,66 @@ >+2018-06-22 Youenn Fablet <youenn@apple.com> >+ >+ Add API to control mock media devices >+ https://bugs.webkit.org/show_bug.cgi?id=186958 >+ >+ Reviewed by NOBODY (OOPS!). >+ >+ Test: fast/mediastream/device-change-event-2.html >+ >+ 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. >+ >+ * WebCore.xcodeproj/project.pbxproj: >+ * platform/mock/MockMediaDevice.h: Added. >+ * platform/mediastream/RealtimeMediaSourceCenter.h: >+ * platform/mock/MockRealtimeAudioSource.cpp: >+ (WebCore::MockRealtimeAudioSource::startProducingData): >+ * platform/mock/MockRealtimeMediaSource.cpp: >+ (WebCore::defaultDevices): >+ (WebCore::devices): >+ (WebCore::deviceMap): >+ (WebCore::MockRealtimeMediaSource::createCaptureDeviceFromMockDevice): >+ (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): >+ * platform/mock/MockRealtimeMediaSource.h: >+ (WebCore::MockMicrophoneProperties::encode const): >+ (WebCore::MockMicrophoneProperties::decode): >+ (WebCore::MockCameraProperties::encode const): >+ (WebCore::MockCameraProperties::decode): >+ (WebCore::MockDisplayProperties::encode const): >+ (WebCore::MockDisplayProperties::decode): >+ (WebCore::MockDevice::isMicrophone const): >+ (WebCore::MockDevice::isCamera const): >+ (WebCore::MockDevice::isDisplay const): >+ (WebCore::MockDevice::type const): >+ (WebCore::MockDevice::encode const): >+ (WebCore::MockDevice::decodeMockDevice): >+ (WebCore::MockDevice::decode): >+ (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-19 Youenn Fablet <youenn@apple.com> > > Need to properly handle removal of worker in SWServer::unregisterServiceWorkerClient timer lambda >diff --git a/Source/WebKit/ChangeLog b/Source/WebKit/ChangeLog >index f8c1e4c67c6db322ebadcb69454cbb31e48960cc..5c6bf24d21aacef3b8090a7ac51c49659ece6932 100644 >--- a/Source/WebKit/ChangeLog >+++ b/Source/WebKit/ChangeLog >@@ -1,3 +1,36 @@ >+2018-06-22 Youenn Fablet <youenn@apple.com> >+ >+ Add API to control mock media devices >+ https://bugs.webkit.org/show_bug.cgi?id=186958 >+ >+ Reviewed by NOBODY (OOPS!). >+ >+ 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-19 Youenn Fablet <youenn@apple.com> > > Network Preflights do not show in WebInspector after moving CORS checks to NetworkProcess >diff --git a/Source/WebCore/WebCore.xcodeproj/project.pbxproj b/Source/WebCore/WebCore.xcodeproj/project.pbxproj >index 4566d7cd34498c159d2454d92160e2d72eeb6d7b..04ed5e3bd88388cbf7604fad83a8d86d08b53499 100644 >--- a/Source/WebCore/WebCore.xcodeproj/project.pbxproj >+++ b/Source/WebCore/WebCore.xcodeproj/project.pbxproj >@@ -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, ); }; }; >@@ -7201,6 +7202,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>"; }; >@@ -18770,6 +18772,7 @@ > 077B64151B95F703003E9AD5 /* MediaPlaybackTargetMock.h */, > 077B64101B94F12E003E9AD5 /* MediaPlaybackTargetPickerMock.cpp */, > 077B64111B94F12E003E9AD5 /* MediaPlaybackTargetPickerMock.h */, >+ 413CCD4820DE013C0065A21A /* MockMediaDevice.h */, > 07D6A4F11BED5F8800174146 /* MockRealtimeAudioSource.cpp */, > 07D6A4F21BED5F8800174146 /* MockRealtimeAudioSource.h */, > 07D6A4ED1BECF2D200174146 /* MockRealtimeMediaSource.cpp */, >@@ -29431,6 +29434,7 @@ > 85031B460A44EFC700F992E0 /* MouseEvent.h in Headers */, > 83765F951DAC522F00C06537 /* MouseEventInit.h in Headers */, > 935C476309AC4CE600A6AAB4 /* MouseEventWithHitTestResults.h in Headers */, >+ 413CCD4A20DE034F0065A21A /* MockMediaDevice.h in Headers */, > 85031B480A44EFC700F992E0 /* MouseRelatedEvent.h in Headers */, > 93309DFC099E64920056E581 /* MoveSelectionCommand.h in Headers */, > FDB1700614A2BAB200A2B5D9 /* MultiChannelResampler.h in Headers */, >diff --git a/Source/WebCore/platform/mediastream/RealtimeMediaSourceCenter.h b/Source/WebCore/platform/mediastream/RealtimeMediaSourceCenter.h >index 0c725f9809d6be97393ccb33dff7d81916598f9d..61ff0eaae564904723c4cb7002f55b4fe48d2999 100644 >--- a/Source/WebCore/platform/mediastream/RealtimeMediaSourceCenter.h >+++ b/Source/WebCore/platform/mediastream/RealtimeMediaSourceCenter.h >@@ -88,13 +88,14 @@ public: > using DevicesChangedObserverToken = unsigned; > DevicesChangedObserverToken addDevicesChangedObserver(std::function<void()>&&); > void removeDevicesChangedObserver(DevicesChangedObserverToken); >- void captureDevicesChanged(); > > void setVideoCapturePageState(bool, bool); > > protected: > RealtimeMediaSourceCenter(); > >+ void captureDevicesChanged(); >+ > static RealtimeMediaSourceCenter& platformCenter(); > RealtimeMediaSourceSupportedConstraints m_supportedConstraints; > >diff --git a/Source/WebCore/platform/mock/MockMediaDevice.h b/Source/WebCore/platform/mock/MockMediaDevice.h >new file mode 100644 >index 0000000000000000000000000000000000000000..882dbaf10e7d6ada06656ce1871cd20ea5b84e4a >--- /dev/null >+++ b/Source/WebCore/platform/mock/MockMediaDevice.h >@@ -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) >diff --git a/Source/WebCore/platform/mock/MockRealtimeAudioSource.cpp b/Source/WebCore/platform/mock/MockRealtimeAudioSource.cpp >index 9c6024e53a8a00edfe381c3118eac92e58133d7c..002caf31236ecb646bf82441182cb1508746c002 100644 >--- a/Source/WebCore/platform/mock/MockRealtimeAudioSource.cpp >+++ b/Source/WebCore/platform/mock/MockRealtimeAudioSource.cpp >@@ -118,7 +118,7 @@ void MockRealtimeAudioSource::startProducingData() > #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()); >diff --git a/Source/WebCore/platform/mock/MockRealtimeMediaSource.cpp b/Source/WebCore/platform/mock/MockRealtimeMediaSource.cpp >index e2e8f239d4def3339dc8856420fa3934a0d27553..b3f4f6edfc4596af26cfcb1ba8c644de17e5668b 100644 >--- a/Source/WebCore/platform/mock/MockRealtimeMediaSource.cpp >+++ b/Source/WebCore/platform/mock/MockRealtimeMediaSource.cpp >@@ -44,116 +44,171 @@ > > namespace WebCore { > >-struct MockDeviceInfo { >- const char* id; >- CaptureDevice::DeviceType type; >- const char* name; >- MockRealtimeMediaSource::MockDevice device; >-}; >- >-static const HashMap<String, MockDeviceInfo>& deviceMap() >-{ >- static const auto infoMap = makeNeverDestroyed([] { >- static const MockDeviceInfo devices[] = { >- { "239c24b0-2b15-11e3-8224-0800200c9a66", CaptureDevice::DeviceType::Microphone, "Mock audio device 1", MockRealtimeMediaSource::MockDevice::Microphone1 }, >- { "239c24b1-2b15-11e3-8224-0800200c9a66", CaptureDevice::DeviceType::Microphone, "Mock audio device 2", MockRealtimeMediaSource::MockDevice::Microphone2 }, >- >- { "239c24b2-2b15-11e3-8224-0800200c9a66", CaptureDevice::DeviceType::Camera, "Mock video device 1", MockRealtimeMediaSource::MockDevice::Camera1 }, >- { "239c24b3-2b15-11e3-8224-0800200c9a66", CaptureDevice::DeviceType::Camera, "Mock video device 2", MockRealtimeMediaSource::MockDevice::Camera2 }, >- >- { "SCREEN-1", CaptureDevice::DeviceType::Screen, "Mock screen device 1", MockRealtimeMediaSource::MockDevice::Screen1 }, >- { "SCREEN-2", CaptureDevice::DeviceType::Screen, "Mock screen device 2", MockRealtimeMediaSource::MockDevice::Screen2 }, >- }; >- >- HashMap<String, MockDeviceInfo> map; >- for (auto& info : devices) >- map.add(ASCIILiteral(info.id), info); >+static inline Vector<MockMediaDevice> defaultDevices() >+{ >+ return Vector<MockMediaDevice> { >+ MockMediaDevice { "239c24b0-2b15-11e3-8224-0800200c9a66", "Mock audio device 1", MockMicrophoneProperties { 44100 } }, >+ MockMediaDevice { "239c24b1-2b15-11e3-8224-0800200c9a66", "Mock audio device 2", MockMicrophoneProperties { 48000 } }, >+ >+ MockMediaDevice { "239c24b2-2b15-11e3-8224-0800200c9a66", "Mock video device 1", MockCameraProperties { 30, RealtimeMediaSourceSettings::VideoFacingMode::User, Color::black } }, >+ MockMediaDevice { "239c24b3-2b15-11e3-8224-0800200c9a66", "Mock video device 2", MockCameraProperties { 15, RealtimeMediaSourceSettings::VideoFacingMode::Environment, Color::darkGray } }, >+ >+ MockMediaDevice { "SCREEN-1", "Mock screen device 1", MockDisplayProperties { 30, Color::lightGray } }, >+ MockMediaDevice { "SCREEN-2", "Mock screen device 2", MockDisplayProperties { 10, Color::yellow } } >+ }; >+} >+ >+static Vector<MockMediaDevice>& devices() >+{ >+ static auto devices = makeNeverDestroyed([] { >+ return defaultDevices(); >+ }()); >+ return devices; >+} >+ >+static HashMap<String, MockMediaDevice>& deviceMap() >+{ >+ static auto map = makeNeverDestroyed([] { >+ HashMap<String, MockMediaDevice> map; >+ for (auto& device : devices()) >+ map.add(device.persistentId, device); >+ > return map; > }()); >+ return map; >+} > >- return infoMap; >+void MockRealtimeMediaSource::createCaptureDevice(const MockMediaDevice& device) >+{ >+ if (device.isMicrophone()) { >+ audioDevices().append(captureDeviceWithPersistentID(CaptureDevice::DeviceType::Microphone, device.persistentId).value()); >+ return; >+ } >+ if (device.isCamera()) { >+ videoDevices().append(captureDeviceWithPersistentID(CaptureDevice::DeviceType::Camera, device.persistentId).value()); >+ return; >+ } >+ ASSERT(device.isDisplay()); >+ displayDevices().append(captureDeviceWithPersistentID(CaptureDevice::DeviceType::Screen, device.persistentId).value()); > } > >-std::optional<CaptureDevice> MockRealtimeMediaSource::captureDeviceWithPersistentID(CaptureDevice::DeviceType type, const String& id) >+void MockRealtimeMediaSource::resetDevices() > { >- ASSERT(!id.isEmpty()); >+ 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(); > >- 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); >+ 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) >+{ >+ auto& map = deviceMap(); >+ auto iterator = map.find(persistentId); >+ if (iterator == map.end()) >+ return; >+ >+ devices().removeFirstMatching([&persistentId](const MockMediaDevice& device) { >+ return device.persistentId == persistentId; >+ }); >+ >+ auto matchCaptureDeviceCriteria = [&persistentId](const CaptureDevice& device) { >+ return device.persistentId() == persistentId; >+ }; >+ >+ auto& device = iterator->value; >+ if (device.isMicrophone()) >+ audioDevices().removeFirstMatching(matchCaptureDeviceCriteria); >+ else if (device.isCamera()) >+ videoDevices().removeFirstMatching(matchCaptureDeviceCriteria); >+ else { >+ ASSERT(device.isDisplay()); >+ displayDevices().removeFirstMatching(matchCaptureDeviceCriteria); >+ } >+ >+ map.remove(iterator); >+} >+ >+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::Microphone, ASCIILiteral("239c24b0-2b15-11e3-8224-0800200c9a66")); >- 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::Microphone, ASCIILiteral("239c24b1-2b15-11e3-8224-0800200c9a66")); >- 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 info = makeNeverDestroyed([] { >- Vector<CaptureDevice> vector; >- >- auto captureDevice = captureDeviceWithPersistentID(CaptureDevice::DeviceType::Camera, ASCIILiteral("239c24b2-2b15-11e3-8224-0800200c9a66")); >- ASSERT(captureDevice); >- vector.append(WTFMove(captureDevice.value())); >- >- captureDevice = captureDeviceWithPersistentID(CaptureDevice::DeviceType::Camera, ASCIILiteral("239c24b3-2b15-11e3-8224-0800200c9a66")); >- ASSERT(captureDevice); >- vector.append(WTFMove(captureDevice.value())); >- >- return vector; >+ 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 info; >+ return videoDevices; > } > > Vector<CaptureDevice>& MockRealtimeMediaSource::displayDevices() > { >- static auto devices = makeNeverDestroyed([] { >- Vector<CaptureDevice> vector; >- >- auto captureDevice = captureDeviceWithPersistentID(CaptureDevice::DeviceType::Screen, ASCIILiteral("SCREEN-1")); >- ASSERT(captureDevice); >- vector.append(WTFMove(captureDevice.value())); >- >- captureDevice = captureDeviceWithPersistentID(CaptureDevice::DeviceType::Screen, ASCIILiteral("SCREEN-2")); >- 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)); > } > >diff --git a/Source/WebCore/platform/mock/MockRealtimeMediaSource.h b/Source/WebCore/platform/mock/MockRealtimeMediaSource.h >index a1d3e9b61b6113365a784300283b94a5e11fa75f..3355da661ec60e9df1a251c000ab56971cf8cb1c 100644 >--- a/Source/WebCore/platform/mock/MockRealtimeMediaSource.h >+++ b/Source/WebCore/platform/mock/MockRealtimeMediaSource.h >@@ -32,27 +32,32 @@ > > #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(); > > 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 @@ protected: > > 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(); >diff --git a/Source/WebCore/platform/mock/MockRealtimeMediaSourceCenter.cpp b/Source/WebCore/platform/mock/MockRealtimeMediaSourceCenter.cpp >index 77a0f8edd3cb7f6ae233b750301215368200701c..df91ebe0fe8544114a662c76e42afca7a700edac 100644 >--- a/Source/WebCore/platform/mock/MockRealtimeMediaSourceCenter.cpp >+++ b/Source/WebCore/platform/mock/MockRealtimeMediaSourceCenter.cpp >@@ -37,16 +37,39 @@ > > namespace WebCore { > >-void MockRealtimeMediaSourceCenter::setMockRealtimeMediaSourceCenterEnabled(bool enabled) >+MockRealtimeMediaSourceCenter& MockRealtimeMediaSourceCenter::singleton() > { > static NeverDestroyed<MockRealtimeMediaSourceCenter> center; >+ return center; >+} >+ >+void MockRealtimeMediaSourceCenter::setMockRealtimeMediaSourceCenterEnabled(bool enabled) >+{ > static bool active = false; > if (active != enabled) { > active = enabled; >- RealtimeMediaSourceCenter::setSharedStreamCenterOverride(enabled ? ¢er.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) >diff --git a/Source/WebCore/platform/mock/MockRealtimeMediaSourceCenter.h b/Source/WebCore/platform/mock/MockRealtimeMediaSourceCenter.h >index 0f92f9d43f989ba6e8c3aa8f35c404eb8b429f3f..be47a0e3e46211d4effed02c1d716579a1c45752 100644 >--- a/Source/WebCore/platform/mock/MockRealtimeMediaSourceCenter.h >+++ b/Source/WebCore/platform/mock/MockRealtimeMediaSourceCenter.h >@@ -39,6 +39,10 @@ class MockRealtimeMediaSourceCenter final : public RealtimeMediaSourceCenter { > 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 @@ private: > MockRealtimeMediaSourceCenter() = default; > friend NeverDestroyed<MockRealtimeMediaSourceCenter>; > >+ static MockRealtimeMediaSourceCenter& singleton(); >+ > RealtimeMediaSource::AudioCaptureFactory& audioFactory() final { return MockRealtimeAudioSource::factory(); } > RealtimeMediaSource::VideoCaptureFactory& videoFactory() final { return MockRealtimeVideoSource::factory(); } > >diff --git a/Source/WebCore/platform/mock/MockRealtimeVideoSource.cpp b/Source/WebCore/platform/mock/MockRealtimeVideoSource.cpp >index ededa83a0e3c5772bd70c8b74dd98e4e062dc28a..799614a9001f7d9978998e6889787cf5228b199a 100644 >--- a/Source/WebCore/platform/mock/MockRealtimeVideoSource.cpp >+++ b/Source/WebCore/platform/mock/MockRealtimeVideoSource.cpp >@@ -108,31 +108,18 @@ MockRealtimeVideoSource::MockRealtimeVideoSource(const String& deviceID, const S > : 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::updateSettings(RealtimeMediaSourceSettings& settin > 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 @@ void MockRealtimeVideoSource::drawText(GraphicsContext& context) > 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 @@ void MockRealtimeVideoSource::generateFrame() > 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()) { >diff --git a/Source/WebCore/platform/mock/MockRealtimeVideoSource.h b/Source/WebCore/platform/mock/MockRealtimeVideoSource.h >index bd526826ff0482b44fc49a4c8607b6668094cf47..a6589b875487704e8b4887a452ee37d97710a60d 100644 >--- a/Source/WebCore/platform/mock/MockRealtimeVideoSource.h >+++ b/Source/WebCore/platform/mock/MockRealtimeVideoSource.h >@@ -83,8 +83,8 @@ private: > > 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 }; >diff --git a/Source/WebKit/CMakeLists.txt b/Source/WebKit/CMakeLists.txt >index bd9de34ed2bff930a6dc30a0e4c737908887f210..422e5242d69e23bf11df69d978329c571b08a186 100644 >--- a/Source/WebKit/CMakeLists.txt >+++ b/Source/WebKit/CMakeLists.txt >@@ -402,6 +402,7 @@ set(WebKit_SOURCES > 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 >diff --git a/Source/WebKit/UIProcess/API/C/WKMockMediaDevice.cpp b/Source/WebKit/UIProcess/API/C/WKMockMediaDevice.cpp >new file mode 100644 >index 0000000000000000000000000000000000000000..fdd060c2393dc5745ab3683bda1fad6df5a174b4 >--- /dev/null >+++ b/Source/WebKit/UIProcess/API/C/WKMockMediaDevice.cpp >@@ -0,0 +1,68 @@ >+/* >+ * 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/MockRealtimeMediaSource.h> >+ >+using namespace WebKit; >+ >+using Properties = Variant<WebCore::MockMicrophoneProperties, WebCore::MockCameraProperties, WebCore::MockDisplayProperties>; >+static inline std::optional<Properties> typeFromString(const String& type) >+{ >+ if (type == "camera") >+ return Properties { WebCore::MockCameraProperties { } }; >+ if (type == "microphone") >+ return Properties { WebCore::MockMicrophoneProperties { } }; >+ if (type == "screen") >+ return Properties { WebCore::MockDisplayProperties { } }; >+ return std::nullopt; >+} >+ >+void WKAddMockMediaDevice(WKContextRef context, WKStringRef persistentId, WKStringRef label, WKStringRef type) >+{ >+ if (auto properties = typeFromString(WebKit::toImpl(type)->string())) >+ toImpl(context)->addMockMediaDevice({ WebKit::toImpl(persistentId)->string(), WebKit::toImpl(label)->string(), WTFMove(*properties) }); >+} >+ >+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(); >+} >diff --git a/Source/WebKit/UIProcess/API/C/WKMockMediaDevice.h b/Source/WebKit/UIProcess/API/C/WKMockMediaDevice.h >new file mode 100644 >index 0000000000000000000000000000000000000000..f776d281711949a10ec70d421cab6a035b074a1a >--- /dev/null >+++ b/Source/WebKit/UIProcess/API/C/WKMockMediaDevice.h >@@ -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 >diff --git a/Source/WebKit/UIProcess/WebProcessPool.cpp b/Source/WebKit/UIProcess/WebProcessPool.cpp >index 7c6cec014ffd74e1ac52be4491c3743e85e10811..beb7b7b06a1b542cf762325d80d354bcadab6368 100644 >--- a/Source/WebKit/UIProcess/WebProcessPool.cpp >+++ b/Source/WebKit/UIProcess/WebProcessPool.cpp >@@ -82,6 +82,7 @@ > #include <JavaScriptCore/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 @@ void WebProcessPool::unregisterSuspendedPageProxy(SuspendedPageProxy& page) > 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 >diff --git a/Source/WebKit/UIProcess/WebProcessPool.h b/Source/WebKit/UIProcess/WebProcessPool.h >index aeb1910a60e45af0255c05e7edccbbdb1693b8f0..83b063e9e5df516c0dadfefd3b92bc549a17244a 100644 >--- a/Source/WebKit/UIProcess/WebProcessPool.h >+++ b/Source/WebKit/UIProcess/WebProcessPool.h >@@ -82,6 +82,10 @@ class Navigation; > class PageConfiguration; > } > >+namespace WebCore { >+struct MockMediaDevice; >+} >+ > namespace WebKit { > > class DownloadProxy; >@@ -454,6 +458,11 @@ public: > > void screenPropertiesStateChanged(); > >+ void addMockMediaDevice(const WebCore::MockMediaDevice&); >+ void clearMockMediaDevices(); >+ void removeMockMediaDevice(const String& persistentId); >+ void resetMockMediaDevices(); >+ > private: > void platformInitialize(); > >diff --git a/Source/WebKit/WebKit.xcodeproj/project.pbxproj b/Source/WebKit/WebKit.xcodeproj/project.pbxproj >index 6a50721ee229997a95726eab07e9182652cdf2a5..0863f995885cbe962243d26a94efcf1775b7f566 100644 >--- a/Source/WebKit/WebKit.xcodeproj/project.pbxproj >+++ b/Source/WebKit/WebKit.xcodeproj/project.pbxproj >@@ -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 */, >diff --git a/Source/WebKit/WebProcess/WebProcess.cpp b/Source/WebKit/WebProcess/WebProcess.cpp >index 6492bebbfe86f5e42e1e53f4b1ab6b35887d1630..9a9c6a34c77e57eba255209a12ae8b42a05d673c 100644 >--- a/Source/WebKit/WebProcess/WebProcess.cpp >+++ b/Source/WebKit/WebProcess/WebProcess.cpp >@@ -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 @@ void WebProcess::setScreenProperties(const WebCore::ScreenProperties& properties > } > #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 >diff --git a/Source/WebKit/WebProcess/WebProcess.h b/Source/WebKit/WebProcess/WebProcess.h >index b8520acd2bd83c4915713fd54340efeb456dcefb..88cc21f9f510980b006f5ce782628435af6ac26b 100644 >--- a/Source/WebKit/WebProcess/WebProcess.h >+++ b/Source/WebKit/WebProcess/WebProcess.h >@@ -69,6 +69,7 @@ class ResourceRequest; > class UserGestureToken; > struct MessagePortIdentifier; > struct MessageWithMessagePorts; >+struct MockMediaDevice; > struct PluginInfo; > struct SecurityOriginData; > struct SoupNetworkProxySettings; >@@ -359,6 +360,13 @@ private: > 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 >diff --git a/Source/WebKit/WebProcess/WebProcess.messages.in b/Source/WebKit/WebProcess/WebProcess.messages.in >index 5ab522be391348811b6daa37c793c9a0c4f79827..0db8bd943beed8353292c90cdc18ea6c27c1505a 100644 >--- a/Source/WebKit/WebProcess/WebProcess.messages.in >+++ b/Source/WebKit/WebProcess/WebProcess.messages.in >@@ -139,4 +139,11 @@ messages -> WebProcess LegacyReceiver { > #if PLATFORM(COCOA) > SetMediaMIMETypes(Vector<String> types) > #endif >+ >+#if ENABLE(MEDIA_STREAM) >+ AddMockMediaDevice(struct WebCore::MockMediaDevice device); >+ ClearMockMediaDevices(); >+ RemoveMockMediaDevice(String persistentId); >+ ResetMockMediaDevices(); >+#endif > } >diff --git a/Tools/ChangeLog b/Tools/ChangeLog >index a60c381fafda3bee0b3670705a9828b69fc7a2f1..987fa337ed55dd763eac5fb3c3c5e5edfefb3d63 100644 >--- a/Tools/ChangeLog >+++ b/Tools/ChangeLog >@@ -1,3 +1,31 @@ >+2018-06-22 Youenn Fablet <youenn@apple.com> >+ >+ Add API to control mock media devices >+ https://bugs.webkit.org/show_bug.cgi?id=186958 >+ >+ Reviewed by NOBODY (OOPS!). >+ >+ 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::addMockDevice): >+ (WTR::TestController::clearMockMediaDevices): >+ (WTR::TestController::removeMockMediaDevice): >+ (WTR::TestController::resetMockMediaDevices): >+ * WebKitTestRunner/TestController.h: >+ * WebKitTestRunner/TestInvocation.cpp: >+ (WTR::TestInvocation::didReceiveSynchronousMessageFromInjectedBundle): >+ > 2018-06-18 Robin Morisset <rmorisset@apple.com> > > [WSL] Starting to write the spec >diff --git a/Tools/WebKitTestRunner/InjectedBundle/Bindings/TestRunner.idl b/Tools/WebKitTestRunner/InjectedBundle/Bindings/TestRunner.idl >index 7e7659cc3bffce0aa876dddc9f02d04976a3db9f..1791668127a6660772ca191c05839d6cc08f3964 100644 >--- a/Tools/WebKitTestRunner/InjectedBundle/Bindings/TestRunner.idl >+++ b/Tools/WebKitTestRunner/InjectedBundle/Bindings/TestRunner.idl >@@ -336,4 +336,11 @@ interface TestRunner { > 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(); > }; >diff --git a/Tools/WebKitTestRunner/InjectedBundle/TestRunner.cpp b/Tools/WebKitTestRunner/InjectedBundle/TestRunner.cpp >index 2831a87b97150279853401943ddc4f9f32a63cc2..95aaef4cda0f88c28a1df8e3efa2c551ea7b73d8 100644 >--- a/Tools/WebKitTestRunner/InjectedBundle/TestRunner.cpp >+++ b/Tools/WebKitTestRunner/InjectedBundle/TestRunner.cpp >@@ -1971,6 +1971,71 @@ void TestRunner::callDidReceiveAllStorageAccessEntriesCallback(Vector<String>& d > 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) > { >diff --git a/Tools/WebKitTestRunner/InjectedBundle/TestRunner.h b/Tools/WebKitTestRunner/InjectedBundle/TestRunner.h >index f2901bc62e6210f4071f287a432efb17eb3c9d69..789ba2302368309ca099a1efb7457e17a25326f2 100644 >--- a/Tools/WebKitTestRunner/InjectedBundle/TestRunner.h >+++ b/Tools/WebKitTestRunner/InjectedBundle/TestRunner.h >@@ -446,6 +446,13 @@ public: > 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 @@ private: > 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; >diff --git a/Tools/WebKitTestRunner/TestController.cpp b/Tools/WebKitTestRunner/TestController.cpp >index ba85189549dd37509eb3e00e8373816e380f3c3a..377ccfe2c3e6096edbaaefc2afa7648d03de7648 100644 >--- a/Tools/WebKitTestRunner/TestController.cpp >+++ b/Tools/WebKitTestRunner/TestController.cpp >@@ -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 @@ void TestController::statisticsResetToConsistentState() > 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 > { >diff --git a/Tools/WebKitTestRunner/TestController.h b/Tools/WebKitTestRunner/TestController.h >index f33783443ef62ab0cddf8898aae0767adde1cb21..a48103fad7a538605f99172eda2cd1059c17448e 100644 >--- a/Tools/WebKitTestRunner/TestController.h >+++ b/Tools/WebKitTestRunner/TestController.h >@@ -213,6 +213,11 @@ public: > 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; >diff --git a/Tools/WebKitTestRunner/TestInvocation.cpp b/Tools/WebKitTestRunner/TestInvocation.cpp >index 52475dfe479b06321642caad3e903d03a7695e9b..05c3ce61a8bef3e89569fc56bc3c97b2d7888760 100644 >--- a/Tools/WebKitTestRunner/TestInvocation.cpp >+++ b/Tools/WebKitTestRunner/TestInvocation.cpp >@@ -916,6 +916,39 @@ WKRetainPtr<WKTypeRef> TestInvocation::didReceiveSynchronousMessageFromInjectedB > 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()); >diff --git a/LayoutTests/ChangeLog b/LayoutTests/ChangeLog >index f63f9e3cfc7220c8cc71a5a0f2d1275fe40d0776..b808a4ffd68fb619d59682617fde650b4035cf8c 100644 >--- a/LayoutTests/ChangeLog >+++ b/LayoutTests/ChangeLog >@@ -1,3 +1,13 @@ >+2018-06-22 Youenn Fablet <youenn@apple.com> >+ >+ Add API to control mock media devices >+ https://bugs.webkit.org/show_bug.cgi?id=186958 >+ >+ Reviewed by NOBODY (OOPS!). >+ >+ * fast/mediastream/device-change-event-2-expected.txt: Added. >+ * fast/mediastream/device-change-event-2.html: Added. >+ > 2018-06-19 Youenn Fablet <youenn@apple.com> > > Network Preflights do not show in WebInspector after moving CORS checks to NetworkProcess >diff --git a/LayoutTests/fast/mediastream/device-change-event-2-expected.txt b/LayoutTests/fast/mediastream/device-change-event-2-expected.txt >new file mode 100644 >index 0000000000000000000000000000000000000000..64c6b61076faaa3de4f8168f7969cf10f607a69d >--- /dev/null >+++ b/LayoutTests/fast/mediastream/device-change-event-2-expected.txt >@@ -0,0 +1,3 @@ >+ >+PASS 'devicechange' event fired when device list changes >+ >diff --git a/LayoutTests/fast/mediastream/device-change-event-2.html b/LayoutTests/fast/mediastream/device-change-event-2.html >new file mode 100644 >index 0000000000000000000000000000000000000000..6dd32b6df2e9c868b1fdea56b2699abdc9fa9c28 >--- /dev/null >+++ b/LayoutTests/fast/mediastream/device-change-event-2.html >@@ -0,0 +1,52 @@ >+<!DOCTYPE html> >+<html> >+<head> >+ <meta charset="utf-8"> >+ <title>Testing local audio capture playback causes "playing" event to fire</title> >+ <script src="../../resources/testharness.js"></script> >+ <script src="../../resources/testharnessreport.js"></script> >+ <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; >+ testRunner.addMockCameraDevice("id1", "my camera"); >+ setTimeout(() => reject("wait 1"), 5000); >+ }); >+ 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; >+ testRunner.addMockMicrophoneDevice("id2", "my mic"); >+ setTimeout(() => reject("wait 1"), 5000); >+ }); >+ 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>
You cannot view the attachment while viewing its details because your browser does not support IFRAMEs.
View the attachment on a separate page
.
View Attachment As Diff
View Attachment As Raw
Actions:
View
|
Formatted Diff
|
Diff
Attachments on
bug 186958
:
343414
|
343418
|
343441
|
343508
|
343517