Diff
Modified: trunk/LayoutTests/ChangeLog (226411 => 226412)
--- trunk/LayoutTests/ChangeLog 2018-01-04 18:58:56 UTC (rev 226411)
+++ trunk/LayoutTests/ChangeLog 2018-01-04 20:12:27 UTC (rev 226412)
@@ -1,3 +1,14 @@
+2018-01-04 Eric Carlson <[email protected]>
+
+ [MediaStream] Add Mock screen capture source
+ https://bugs.webkit.org/show_bug.cgi?id=181291
+ <rdar://problem/36298164>
+
+ Reviewed by Dean Jackson.
+
+ * http/tests/media/media-stream/get-display-media-prompt-expected.txt: Added.
+ * http/tests/media/media-stream/get-display-media-prompt.html: Added.
+
2018-01-04 John Wilander <[email protected]>
Storage Access API: Remove _javascript_ confirm() prompt from Document::requestStorageAccess()
Added: trunk/LayoutTests/http/tests/media/media-stream/get-display-media-prompt-expected.txt (0 => 226412)
--- trunk/LayoutTests/http/tests/media/media-stream/get-display-media-prompt-expected.txt (rev 0)
+++ trunk/LayoutTests/http/tests/media/media-stream/get-display-media-prompt-expected.txt 2018-01-04 20:12:27 UTC (rev 226412)
@@ -0,0 +1,32 @@
+Test basic getDisplayMedia prompting behavior
+
+On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
+
+
+PASS numberOfTimesGetUserMediaPromptHasBeenCalled() is 0
+
+** Request an audio-only stream, the user should be prompted **
+PASS numberOfTimesGetUserMediaPromptHasBeenCalled() is 1
+PASS stream.getAudioTracks().length is 1
+PASS stream.getVideoTracks().length is 0
+
+** Request an video-only stream, the user should be prompted **
+PASS numberOfTimesGetUserMediaPromptHasBeenCalled() is 2
+PASS stream.getAudioTracks().length is 0
+PASS stream.getVideoTracks().length is 1
+
+** Request a stream with audio and video, the user should be prompted **
+PASS numberOfTimesGetUserMediaPromptHasBeenCalled() is 3
+PASS stream.getAudioTracks().length is 1
+PASS stream.getVideoTracks().length is 1
+
+** Request a stream with invalid constraints, the user should not be prompted **
+PASS numberOfTimesGetUserMediaPromptHasBeenCalled() is 3
+PASS stream is null
+PASS err instanceof Error is true
+PASS err.name is "InvalidAccessError"
+
+PASS successfullyParsed is true
+
+TEST COMPLETE
+
Added: trunk/LayoutTests/http/tests/media/media-stream/get-display-media-prompt.html (0 => 226412)
--- trunk/LayoutTests/http/tests/media/media-stream/get-display-media-prompt.html (rev 0)
+++ trunk/LayoutTests/http/tests/media/media-stream/get-display-media-prompt.html 2018-01-04 20:12:27 UTC (rev 226412)
@@ -0,0 +1,80 @@
+<!DOCTYPE html>
+<html>
+ <head>
+ <title>getDisplayMedia prompt</title>
+ <script src=""
+ </head>
+ <body>
+ <p id="description"></p>
+ <div id="console"></div>
+
+<script>
+
+ let stream;
+ let err;
+
+ function numberOfTimesGetUserMediaPromptHasBeenCalled() {
+ return testRunner.userMediaPermissionRequestCountForOrigin(document.location.href, document.location.href);
+ }
+
+ async function promptForAudioOnly() {
+ debug("<br>** Request an audio-only stream, the user should be prompted **");
+ stream = await navigator.mediaDevices.getDisplayMedia({ audio: true });
+ shouldBe("numberOfTimesGetUserMediaPromptHasBeenCalled()", "1");
+ shouldBe("stream.getAudioTracks().length", "1");
+ shouldBe("stream.getVideoTracks().length", "0");
+ }
+
+ async function promptForVideoOnly() {
+ debug("<br>** Request an video-only stream, the user should be prompted **");
+ stream = await navigator.mediaDevices.getDisplayMedia({ video: true });
+ shouldBe("numberOfTimesGetUserMediaPromptHasBeenCalled()", "2");
+ shouldBe("stream.getAudioTracks().length", "0");
+ shouldBe("stream.getVideoTracks().length", "1");
+ }
+
+ async function promptForAudioAndVideo() {
+ debug("<br>** Request a stream with audio and video, the user should be prompted **");
+ stream = await navigator.mediaDevices.getDisplayMedia({ video: true, audio: true });
+ shouldBe("numberOfTimesGetUserMediaPromptHasBeenCalled()", "3");
+ shouldBe("stream.getAudioTracks().length", "1");
+ shouldBe("stream.getVideoTracks().length", "1");
+ }
+
+ async function promptWithMediaTrackConstraints() {
+ debug("<br>** Request a stream with invalid constraints, the user should not be prompted **");
+ stream = null;
+ try {
+ stream = await navigator.mediaDevices.getDisplayMedia({ video: {width: {exact: 640}, height: {exact: 480}} });
+ } catch (e) {
+ err = e;
+ }
+
+ shouldBe("numberOfTimesGetUserMediaPromptHasBeenCalled()", "3");
+ shouldBeNull("stream");
+ shouldBeTrue("err instanceof Error ");
+ shouldBeEqualToString("err.name", "InvalidAccessError");
+ }
+
+ (async function() {
+ description('Test basic getDisplayMedia prompting behavior');
+ jsTestIsAsync = true;
+
+ testRunner.resetUserMediaPermissionRequestCountForOrigin(document.location.href, document.location.href);
+ window.internals.settings.setScreenCaptureEnabled(true);
+
+ shouldBe("numberOfTimesGetUserMediaPromptHasBeenCalled()", "0");
+
+ await promptForAudioOnly();
+ await promptForVideoOnly();
+ await promptForAudioAndVideo();
+ await promptWithMediaTrackConstraints();
+
+ debug("");
+ finishJSTest();
+ })()
+
+</script>
+<script src=""
+</body>
+</html>
\ No newline at end of file
Modified: trunk/Source/WebCore/ChangeLog (226411 => 226412)
--- trunk/Source/WebCore/ChangeLog 2018-01-04 18:58:56 UTC (rev 226411)
+++ trunk/Source/WebCore/ChangeLog 2018-01-04 20:12:27 UTC (rev 226412)
@@ -1,3 +1,91 @@
+2018-01-04 Eric Carlson <[email protected]>
+
+ [MediaStream] Add Mock screen capture source
+ https://bugs.webkit.org/show_bug.cgi?id=181291
+ <rdar://problem/36298164>
+
+ Reviewed by Dean Jackson.
+
+ Tests: http/tests/media/media-stream/get-display-media-prompt.html
+ GetDisplayMediaTest.BasicPrompt
+ GetDisplayMediaTest.Constraints
+
+ * Modules/mediastream/MediaDevices.cpp:
+ (WebCore::MediaDevices::MediaDevices): Add static_assert to ensure MediaDevices::DisplayCaptureSurfaceType
+ and RealtimeMediaSourceSettings::DisplaySurfaceType values are equivalent.
+ (WebCore::MediaDevices::getSupportedConstraints): Remove bogus code.
+ * Modules/mediastream/MediaDevices.h: Add DisplayCaptureSurfaceType.
+ * Modules/mediastream/MediaDevices.idl: Ditto.
+
+ * Modules/mediastream/MediaStreamTrack.cpp:
+ (WebCore::MediaStreamTrack::getSettings const): Add a FIXME.
+ * Modules/mediastream/MediaStreamTrack.h: Add displaySurface and logicalSurface.
+
+ * Modules/mediastream/MediaTrackSupportedConstraints.h: Remove displaySurface and logicalSurface.
+ * Modules/mediastream/MediaTrackSupportedConstraints.idl:
+
+ * SourcesCocoa.txt: Add DisplayCaptureManagerCocoa.cpp and DisplayCaptureSourceCocoa.cpp.
+
+ * WebCore.xcodeproj/project.pbxproj: Ditto.
+
+ * platform/mediastream/CaptureDevice.h:
+ (WebCore::CaptureDevice::encode const): Add.
+ (WebCore::CaptureDevice::decode):
+
+ * platform/mediastream/RealtimeMediaSourceCenter.cpp:
+ (WebCore::RealtimeMediaSourceCenter::getMediaStreamDevices): Include display capture "devices".
+ (WebCore::RealtimeMediaSourceCenter::validateRequestConstraints): Deal with display capture devices.
+ (WebCore::RealtimeMediaSourceCenter::captureDeviceWithPersistentID): Ditto.
+ * platform/mediastream/RealtimeMediaSourceCenter.h:
+
+ * platform/mediastream/RealtimeMediaSourceSettings.h:
+ (WebCore::RealtimeMediaSourceSettings::displaySurface const): Return a DisplaySurfaceType.
+ (WebCore::RealtimeMediaSourceSettings::setDisplaySurface): Take a DisplaySurfaceType.
+
+ * platform/mediastream/mac/DisplayCaptureManagerCocoa.cpp:
+ (WebCore::DisplayCaptureManagerCocoa::singleton):
+ (WebCore::DisplayCaptureManagerCocoa::~DisplayCaptureManagerCocoa):
+ (WebCore::DisplayCaptureManagerCocoa::captureDevices):
+ (WebCore::DisplayCaptureManagerCocoa::screenCaptureDeviceWithPersistentID):
+ (WebCore::DisplayCaptureManagerCocoa::captureDeviceWithPersistentID):
+ * platform/mediastream/mac/DisplayCaptureManagerCocoa.h:
+
+ * platform/mediastream/mac/DisplayCaptureSourceCocoa.cpp: Added.
+ (WebCore::DisplayCaptureSourceCocoa::DisplayCaptureSourceCocoa):
+ (WebCore::DisplayCaptureSourceCocoa::~DisplayCaptureSourceCocoa):
+ (WebCore::DisplayCaptureSourceCocoa::capabilities const):
+ (WebCore::DisplayCaptureSourceCocoa::settings const):
+ (WebCore::DisplayCaptureSourceCocoa::settingsDidChange):
+ (WebCore::DisplayCaptureSourceCocoa::startProducingData):
+ (WebCore::DisplayCaptureSourceCocoa::stopProducingData):
+ (WebCore::DisplayCaptureSourceCocoa::elapsedTime):
+ (WebCore::DisplayCaptureSourceCocoa::applyFrameRate):
+ (WebCore::DisplayCaptureSourceCocoa::emitFrame):
+ * platform/mediastream/mac/DisplayCaptureSourceCocoa.h:
+
+ * platform/mediastream/mac/RealtimeMediaSourceCenterMac.cpp:
+ (WebCore::RealtimeMediaSourceCenterMac::displayCaptureDeviceManager): New.
+ * platform/mediastream/mac/RealtimeMediaSourceCenterMac.h:
+
+ * platform/mock/MockRealtimeMediaSource.cpp:
+ (WebCore::deviceMap): Add screen capture "devices".
+ (WebCore::MockRealtimeMediaSource::displayDevices): New.
+ * platform/mock/MockRealtimeMediaSource.h:
+
+ * platform/mock/MockRealtimeMediaSourceCenter.cpp: Clean up includes.
+ * platform/mock/MockRealtimeMediaSourceCenter.h:
+
+ * platform/mock/MockRealtimeVideoSource.cpp:
+ (WebCore::MockRealtimeVideoSource::MockRealtimeVideoSource): Mock two screen devices.
+ (WebCore::MockRealtimeVideoSource::updateSettings): Deal with mock screens.
+ (WebCore::MockRealtimeVideoSource::initializeCapabilities): Ditto.
+ (WebCore::MockRealtimeVideoSource::initializeSupportedConstraints): Ditto.
+ (WebCore::MockRealtimeVideoSource::drawText): Ditto.
+ (WebCore::MockRealtimeVideoSource::generateFrame): Ditto.
+ * platform/mock/MockRealtimeVideoSource.h:
+ (WebCore::MockRealtimeVideoSource::mockCamera const):
+ (WebCore::MockRealtimeVideoSource::mockScreen const):
+
2018-01-04 Youenn Fablet <[email protected]>
FetchResponse should set its internal response text encoding name
Modified: trunk/Source/WebCore/Modules/mediastream/MediaDevices.cpp (226411 => 226412)
--- trunk/Source/WebCore/Modules/mediastream/MediaDevices.cpp 2018-01-04 18:58:56 UTC (rev 226411)
+++ trunk/Source/WebCore/Modules/mediastream/MediaDevices.cpp 2018-01-04 20:12:27 UTC (rev 226412)
@@ -39,6 +39,7 @@
#include "EventNames.h"
#include "MediaDevicesRequest.h"
#include "MediaTrackSupportedConstraints.h"
+#include "RealtimeMediaSourceSettings.h"
#include "RuntimeEnabledFeatures.h"
#include "UserMediaRequest.h"
#include <wtf/RandomNumber.h>
@@ -59,6 +60,11 @@
if (!m_scheduledEventTimer.isActive())
m_scheduledEventTimer.startOneShot(Seconds(randomNumber() / 2));
});
+
+ 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");
+ 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()
@@ -145,10 +151,6 @@
result.echoCancellation = supported.supportsEchoCancellation();
result.deviceId = supported.supportsDeviceId();
result.groupId = supported.supportsGroupId();
- if (RuntimeEnabledFeatures::sharedFeatures().screenCaptureEnabled()) {
- result.deviceId = supported.supportsDeviceId();
- result.groupId = supported.supportsGroupId();
- }
return result;
}
Modified: trunk/Source/WebCore/Modules/mediastream/MediaDevices.h (226411 => 226412)
--- trunk/Source/WebCore/Modules/mediastream/MediaDevices.h 2018-01-04 18:58:56 UTC (rev 226411)
+++ trunk/Source/WebCore/Modules/mediastream/MediaDevices.h 2018-01-04 20:12:27 UTC (rev 226412)
@@ -60,6 +60,13 @@
using Promise = DOMPromiseDeferred<IDLInterface<MediaStream>>;
using EnumerateDevicesPromise = DOMPromiseDeferred<IDLSequence<IDLInterface<MediaDeviceInfo>>>;
+ enum class DisplayCaptureSurfaceType {
+ Monitor,
+ Window,
+ Application,
+ Browser,
+ };
+
struct StreamConstraints {
Variant<bool, MediaTrackConstraints> video;
Variant<bool, MediaTrackConstraints> audio;
Modified: trunk/Source/WebCore/Modules/mediastream/MediaDevices.idl (226411 => 226412)
--- trunk/Source/WebCore/Modules/mediastream/MediaDevices.idl 2018-01-04 18:58:56 UTC (rev 226411)
+++ trunk/Source/WebCore/Modules/mediastream/MediaDevices.idl 2018-01-04 20:12:27 UTC (rev 226412)
@@ -47,3 +47,13 @@
(boolean or MediaTrackConstraints) video = false;
(boolean or MediaTrackConstraints) audio = false;
};
+
+[
+ Conditional=MEDIA_STREAM,
+ EnabledAtRuntime=ScreenCapture
+] enum DisplayCaptureSurfaceType {
+ "monitor",
+ "window",
+ "application",
+ "browser"
+};
Modified: trunk/Source/WebCore/Modules/mediastream/MediaStreamTrack.cpp (226411 => 226412)
--- trunk/Source/WebCore/Modules/mediastream/MediaStreamTrack.cpp 2018-01-04 18:58:56 UTC (rev 226411)
+++ trunk/Source/WebCore/Modules/mediastream/MediaStreamTrack.cpp 2018-01-04 20:12:27 UTC (rev 226412)
@@ -170,6 +170,9 @@
result.deviceId = RealtimeMediaSourceCenter::singleton().hashStringWithSalt(settings.deviceId(), document.deviceIDHashSalt());
if (settings.supportsGroupId())
result.groupId = RealtimeMediaSourceCenter::singleton().hashStringWithSalt(settings.groupId(), document.deviceIDHashSalt());
+
+ // FIXME: shouldn't this include displaySurface and logicalSurface?
+
return result;
}
Modified: trunk/Source/WebCore/Modules/mediastream/MediaStreamTrack.h (226411 => 226412)
--- trunk/Source/WebCore/Modules/mediastream/MediaStreamTrack.h 2018-01-04 18:58:56 UTC (rev 226411)
+++ trunk/Source/WebCore/Modules/mediastream/MediaStreamTrack.h 2018-01-04 20:12:27 UTC (rev 226412)
@@ -95,6 +95,8 @@
std::optional<int> sampleRate;
std::optional<int> sampleSize;
std::optional<bool> echoCancellation;
+ std::optional<bool> displaySurface;
+ String logicalSurface;
String deviceId;
String groupId;
};
Modified: trunk/Source/WebCore/Modules/mediastream/MediaTrackSupportedConstraints.h (226411 => 226412)
--- trunk/Source/WebCore/Modules/mediastream/MediaTrackSupportedConstraints.h 2018-01-04 18:58:56 UTC (rev 226411)
+++ trunk/Source/WebCore/Modules/mediastream/MediaTrackSupportedConstraints.h 2018-01-04 20:12:27 UTC (rev 226412)
@@ -46,8 +46,6 @@
bool echoCancellation;
bool deviceId;
bool groupId;
- bool displaySurface;
- bool logicalSurface;
};
} // namespace WebCore
Modified: trunk/Source/WebCore/Modules/mediastream/MediaTrackSupportedConstraints.idl (226411 => 226412)
--- trunk/Source/WebCore/Modules/mediastream/MediaTrackSupportedConstraints.idl 2018-01-04 18:58:56 UTC (rev 226411)
+++ trunk/Source/WebCore/Modules/mediastream/MediaTrackSupportedConstraints.idl 2018-01-04 20:12:27 UTC (rev 226412)
@@ -45,6 +45,4 @@
// FIXME 169871: add channelCount
boolean deviceId = true;
boolean groupId = true;
- boolean displaySurface = true;
- boolean logicalSurface = true;
};
Modified: trunk/Source/WebCore/SourcesCocoa.txt (226411 => 226412)
--- trunk/Source/WebCore/SourcesCocoa.txt 2018-01-04 18:58:56 UTC (rev 226411)
+++ trunk/Source/WebCore/SourcesCocoa.txt 2018-01-04 20:12:27 UTC (rev 226412)
@@ -354,6 +354,8 @@
rendering/TextAutoSizing.cpp
platform/mediastream/mac/CoreAudioCaptureSource.cpp
+platform/mediastream/mac/DisplayCaptureManagerCocoa.cpp
+platform/mediastream/mac/DisplayCaptureSourceCocoa.cpp
platform/mediastream/mac/RealtimeIncomingAudioSourceCocoa.cpp
platform/mediastream/mac/RealtimeIncomingVideoSourceCocoa.cpp
platform/mediastream/mac/RealtimeMediaSourceCenterMac.cpp
Modified: trunk/Source/WebCore/WebCore.xcodeproj/project.pbxproj (226411 => 226412)
--- trunk/Source/WebCore/WebCore.xcodeproj/project.pbxproj 2018-01-04 18:58:56 UTC (rev 226411)
+++ trunk/Source/WebCore/WebCore.xcodeproj/project.pbxproj 2018-01-04 20:12:27 UTC (rev 226412)
@@ -5217,6 +5217,10 @@
079F5E4B0F3BEBEA005E0782 /* MediaPlayerPrivate.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MediaPlayerPrivate.h; sourceTree = "<group>"; };
07A6D1E91491137700051D0C /* MediaFragmentURIParser.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = MediaFragmentURIParser.cpp; sourceTree = "<group>"; };
07A6D1EA1491137700051D0C /* MediaFragmentURIParser.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MediaFragmentURIParser.h; sourceTree = "<group>"; };
+ 07A6D8471FEB700B006441DE /* DisplayCaptureSourceCocoa.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = DisplayCaptureSourceCocoa.cpp; sourceTree = "<group>"; };
+ 07A6D8481FEB700B006441DE /* DisplayCaptureManagerCocoa.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = DisplayCaptureManagerCocoa.cpp; sourceTree = "<group>"; };
+ 07A6D8491FEB700C006441DE /* DisplayCaptureManagerCocoa.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = DisplayCaptureManagerCocoa.h; sourceTree = "<group>"; };
+ 07A6D84A1FEB700D006441DE /* DisplayCaptureSourceCocoa.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = DisplayCaptureSourceCocoa.h; sourceTree = "<group>"; };
07AA6B69166D019500D45671 /* InbandTextTrackPrivateAVFObjC.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = InbandTextTrackPrivateAVFObjC.h; sourceTree = "<group>"; };
07AA6B6A166D019500D45671 /* InbandTextTrackPrivateAVFObjC.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = InbandTextTrackPrivateAVFObjC.mm; sourceTree = "<group>"; };
07AB996518DA3C010018771E /* RTCConfiguration.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RTCConfiguration.h; sourceTree = "<group>"; };
@@ -14826,6 +14830,10 @@
3F8020341E9E381D00DEC61D /* CoreAudioCaptureDeviceManager.h */,
3F3BB5821E709EE400C701F2 /* CoreAudioCaptureSource.cpp */,
3F3BB5831E709EE400C701F2 /* CoreAudioCaptureSource.h */,
+ 07A6D8481FEB700B006441DE /* DisplayCaptureManagerCocoa.cpp */,
+ 07A6D8491FEB700C006441DE /* DisplayCaptureManagerCocoa.h */,
+ 07A6D8471FEB700B006441DE /* DisplayCaptureSourceCocoa.cpp */,
+ 07A6D84A1FEB700D006441DE /* DisplayCaptureSourceCocoa.h */,
0744ECEB1E0C4AE5000D0944 /* MockRealtimeAudioSourceMac.h */,
0744ECEC1E0C4AE5000D0944 /* MockRealtimeAudioSourceMac.mm */,
07EE76ED1BEA619800F89133 /* MockRealtimeVideoSourceMac.h */,
Modified: trunk/Source/WebCore/platform/mediastream/CaptureDevice.h (226411 => 226412)
--- trunk/Source/WebCore/platform/mediastream/CaptureDevice.h 2018-01-04 18:58:56 UTC (rev 226411)
+++ trunk/Source/WebCore/platform/mediastream/CaptureDevice.h 2018-01-04 20:12:27 UTC (rev 226412)
@@ -25,6 +25,7 @@
#pragma once
+#include <wtf/EnumTraits.h>
#include <wtf/text/WTFString.h>
namespace WebCore {
@@ -56,6 +57,51 @@
explicit operator bool() const { return m_type != DeviceType::Unknown; }
+#if ENABLE(MEDIA_STREAM)
+ template<class Encoder>
+ void encode(Encoder& encoder) const
+ {
+ encoder << m_persistentId;
+ encoder << m_label;
+ encoder << m_groupId;
+ encoder << m_enabled;
+ encoder.encodeEnum(m_type);
+ }
+
+ template <class Decoder>
+ static std::optional<CaptureDevice> 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<String> groupId;
+ decoder >> groupId;
+ if (!groupId)
+ return std::nullopt;
+
+ std::optional<bool> enabled;
+ decoder >> enabled;
+ if (!enabled)
+ return std::nullopt;
+
+ std::optional<CaptureDevice::DeviceType> type;
+ decoder >> type;
+ if (!type)
+ return std::nullopt;
+
+ std::optional<CaptureDevice> device = {{ WTFMove(*persistentId), WTFMove(*type), WTFMove(*label), WTFMove(*groupId) }};
+ device->setEnabled(*enabled);
+ return device;
+ }
+#endif
+
private:
String m_persistentId;
DeviceType m_type { DeviceType::Unknown };
@@ -66,3 +112,22 @@
} // namespace WebCore
+#if ENABLE(MEDIA_STREAM)
+namespace WTF {
+
+template<> struct EnumTraits<WebCore::CaptureDevice::DeviceType> {
+ using values = EnumValues<
+ WebCore::CaptureDevice::DeviceType,
+ WebCore::CaptureDevice::DeviceType::Unknown,
+ WebCore::CaptureDevice::DeviceType::Microphone,
+ WebCore::CaptureDevice::DeviceType::Camera,
+ WebCore::CaptureDevice::DeviceType::Screen,
+ WebCore::CaptureDevice::DeviceType::Application,
+ WebCore::CaptureDevice::DeviceType::Window,
+ WebCore::CaptureDevice::DeviceType::Browser
+ >;
+};
+
+} // namespace WTF
+#endif
+
Modified: trunk/Source/WebCore/platform/mediastream/RealtimeMediaSourceCenter.cpp (226411 => 226412)
--- trunk/Source/WebCore/platform/mediastream/RealtimeMediaSourceCenter.cpp 2018-01-04 18:58:56 UTC (rev 226411)
+++ trunk/Source/WebCore/platform/mediastream/RealtimeMediaSourceCenter.cpp 2018-01-04 20:12:27 UTC (rev 226412)
@@ -140,6 +140,10 @@
if (device.enabled())
result.append(device);
}
+ for (auto& device : displayCaptureDeviceManager().captureDevices()) {
+ if (device.enabled())
+ result.append(device);
+ }
return result;
}
@@ -248,13 +252,15 @@
String invalidConstraint;
CaptureSourceOrError sourceOrError;
switch (device.type()) {
- case CaptureDevice::DeviceType::Camera:
- if (request.type == MediaStreamRequest::Type::UserMedia && request.videoConstraints.isValid) {
- auto sourceOrError = videoFactory().createVideoCaptureSource(device, { });
- if (sourceOrError && sourceOrError.captureSource->supportsConstraints(request.videoConstraints, invalidConstraint))
- videoDeviceInfo.append({sourceOrError.captureSource->fitnessScore(), device});
- }
+ case CaptureDevice::DeviceType::Camera: {
+ if (request.type != MediaStreamRequest::Type::UserMedia || !request.videoConstraints.isValid)
+ continue;
+
+ auto sourceOrError = videoFactory().createVideoCaptureSource(device, { });
+ if (sourceOrError && sourceOrError.captureSource->supportsConstraints(request.videoConstraints, invalidConstraint))
+ videoDeviceInfo.append({sourceOrError.captureSource->fitnessScore(), device});
break;
+ }
case CaptureDevice::DeviceType::Microphone:
if (request.audioConstraints.isValid) {
auto sourceOrError = audioFactory().createAudioCaptureSource(device, { });
@@ -265,11 +271,19 @@
case CaptureDevice::DeviceType::Screen:
case CaptureDevice::DeviceType::Application:
case CaptureDevice::DeviceType::Window:
- case CaptureDevice::DeviceType::Browser:
- ASSERT(request.type == MediaStreamRequest::Type::DisplayMedia);
- ASSERT(request.videoConstraints.mandatoryConstraints.isEmpty());
+ case CaptureDevice::DeviceType::Browser: {
+ if (request.type != MediaStreamRequest::Type::DisplayMedia)
+ continue;
+ ASSERT(request.audioConstraints.mandatoryConstraints.isEmpty());
ASSERT(request.videoConstraints.advancedConstraints.isEmpty());
+ if (!request.videoConstraints.isValid || !request.videoConstraints.advancedConstraints.isEmpty() || !request.videoConstraints.mandatoryConstraints.isEmpty())
+ continue;
+
+ auto sourceOrError = videoFactory().createVideoCaptureSource(device, { });
+ if (sourceOrError && sourceOrError.captureSource->supportsConstraints(request.videoConstraints, invalidConstraint))
+ videoDeviceInfo.append({sourceOrError.captureSource->fitnessScore(), device});
break;
+ }
case CaptureDevice::DeviceType::Unknown:
ASSERT_NOT_REACHED();
break;
@@ -321,6 +335,8 @@
case CaptureDevice::DeviceType::Application:
case CaptureDevice::DeviceType::Window:
case CaptureDevice::DeviceType::Browser:
+ return displayCaptureDeviceManager().captureDeviceWithPersistentID(type, id);
+ break;
case CaptureDevice::DeviceType::Unknown:
ASSERT_NOT_REACHED();
break;
Modified: trunk/Source/WebCore/platform/mediastream/RealtimeMediaSourceCenter.h (226411 => 226412)
--- trunk/Source/WebCore/platform/mediastream/RealtimeMediaSourceCenter.h 2018-01-04 18:58:56 UTC (rev 226411)
+++ trunk/Source/WebCore/platform/mediastream/RealtimeMediaSourceCenter.h 2018-01-04 20:12:27 UTC (rev 226412)
@@ -79,6 +79,7 @@
virtual CaptureDeviceManager& audioCaptureDeviceManager() = 0;
virtual CaptureDeviceManager& videoCaptureDeviceManager() = 0;
+ virtual CaptureDeviceManager& displayCaptureDeviceManager() = 0;
String hashStringWithSalt(const String& id, const String& hashSalt);
WEBCORE_EXPORT CaptureDevice captureDeviceWithUniqueID(const String& id, const String& hashSalt);
Modified: trunk/Source/WebCore/platform/mediastream/RealtimeMediaSourceSettings.h (226411 => 226412)
--- trunk/Source/WebCore/platform/mediastream/RealtimeMediaSourceSettings.h 2018-01-04 18:58:56 UTC (rev 226411)
+++ trunk/Source/WebCore/platform/mediastream/RealtimeMediaSourceSettings.h 2018-01-04 20:12:27 UTC (rev 226412)
@@ -89,9 +89,17 @@
const AtomicString& groupId() const { return m_groupId; }
void setGroupId(const AtomicString& groupId) { m_groupId = groupId; }
+ enum class DisplaySurfaceType {
+ Monitor,
+ Window,
+ Application,
+ Browser,
+ Invalid,
+ };
+
bool supportsDisplaySurface() const { return m_supportedConstraints.supportsDisplaySurface(); }
- const AtomicString& displaySurface() const { return m_displaySurface; }
- void setDisplaySurface(const AtomicString& displaySurface) { m_displaySurface = displaySurface; }
+ DisplaySurfaceType displaySurface() const { return m_displaySurface; }
+ void setDisplaySurface(DisplaySurfaceType displaySurface) { m_displaySurface = displaySurface; }
bool supportsLogicalSurface() const { return m_supportedConstraints.supportsLogicalSurface(); }
bool logicalSurface() const { return m_logicalSurface; }
@@ -121,7 +129,7 @@
AtomicString m_groupId;
AtomicString m_label;
- AtomicString m_displaySurface;
+ DisplaySurfaceType m_displaySurface { DisplaySurfaceType::Invalid };
bool m_logicalSurface { 0 };
RealtimeMediaSourceSupportedConstraints m_supportedConstraints;
Copied: trunk/Source/WebCore/platform/mediastream/mac/DisplayCaptureManagerCocoa.cpp (from rev 226411, trunk/Source/WebCore/platform/mock/MockRealtimeMediaSourceCenter.cpp) (0 => 226412)
--- trunk/Source/WebCore/platform/mediastream/mac/DisplayCaptureManagerCocoa.cpp (rev 0)
+++ trunk/Source/WebCore/platform/mediastream/mac/DisplayCaptureManagerCocoa.cpp 2018-01-04 20:12:27 UTC (rev 226412)
@@ -0,0 +1,81 @@
+/*
+ * Copyright (C) 2017 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 "DisplayCaptureManagerCocoa.h"
+
+#if ENABLE(MEDIA_STREAM)
+
+#include "Logging.h"
+#include <wtf/NeverDestroyed.h>
+
+namespace WebCore {
+
+DisplayCaptureManagerCocoa& DisplayCaptureManagerCocoa::singleton()
+{
+ static NeverDestroyed<DisplayCaptureManagerCocoa> manager;
+ return manager.get();
+}
+
+DisplayCaptureManagerCocoa::~DisplayCaptureManagerCocoa()
+{
+}
+
+const Vector<CaptureDevice>& DisplayCaptureManagerCocoa::captureDevices()
+{
+ return m_displays;
+}
+
+std::optional<CaptureDevice> DisplayCaptureManagerCocoa::screenCaptureDeviceWithPersistentID(const String& deviceID)
+{
+ UNUSED_PARAM(deviceID);
+ return std::nullopt;
+}
+
+std::optional<CaptureDevice> DisplayCaptureManagerCocoa::captureDeviceWithPersistentID(CaptureDevice::DeviceType type, const String& id)
+{
+ switch (type) {
+ case CaptureDevice::DeviceType::Screen:
+ return screenCaptureDeviceWithPersistentID(id);
+ break;
+
+ case CaptureDevice::DeviceType::Application:
+ case CaptureDevice::DeviceType::Window:
+ case CaptureDevice::DeviceType::Browser:
+ break;
+
+ case CaptureDevice::DeviceType::Camera:
+ case CaptureDevice::DeviceType::Microphone:
+ case CaptureDevice::DeviceType::Unknown:
+ ASSERT_NOT_REACHED();
+ break;
+ }
+
+ return std::nullopt;
+}
+
+} // namespace WebCore
+
+#endif // ENABLE(MEDIA_STREAM)
Copied: trunk/Source/WebCore/platform/mediastream/mac/DisplayCaptureManagerCocoa.h (from rev 226411, trunk/Source/WebCore/platform/mock/MockRealtimeMediaSourceCenter.cpp) (0 => 226412)
--- trunk/Source/WebCore/platform/mediastream/mac/DisplayCaptureManagerCocoa.h (rev 0)
+++ trunk/Source/WebCore/platform/mediastream/mac/DisplayCaptureManagerCocoa.h 2018-01-04 20:12:27 UTC (rev 226412)
@@ -0,0 +1,51 @@
+/*
+ * Copyright (C) 2017 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
+
+#if ENABLE(MEDIA_STREAM)
+
+#include "CaptureDeviceManager.h"
+
+namespace WebCore {
+
+class DisplayCaptureManagerCocoa final : public CaptureDeviceManager {
+public:
+ static DisplayCaptureManagerCocoa& singleton();
+ DisplayCaptureManagerCocoa() = default;
+
+private:
+ virtual ~DisplayCaptureManagerCocoa();
+
+ const Vector<CaptureDevice>& captureDevices() final;
+ std::optional<CaptureDevice> captureDeviceWithPersistentID(CaptureDevice::DeviceType, const String&) final;
+ std::optional<CaptureDevice> screenCaptureDeviceWithPersistentID(const String&);
+
+ Vector<CaptureDevice> m_displays;
+};
+
+} // namespace WebCore
+
+#endif // ENABLE(MEDIA_STREAM)
Added: trunk/Source/WebCore/platform/mediastream/mac/DisplayCaptureSourceCocoa.cpp (0 => 226412)
--- trunk/Source/WebCore/platform/mediastream/mac/DisplayCaptureSourceCocoa.cpp (rev 0)
+++ trunk/Source/WebCore/platform/mediastream/mac/DisplayCaptureSourceCocoa.cpp 2018-01-04 20:12:27 UTC (rev 226412)
@@ -0,0 +1,148 @@
+/*
+ * Copyright (C) 2017 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 "DisplayCaptureSourceCocoa.h"
+
+#if ENABLE(MEDIA_STREAM)
+
+#include "Logging.h"
+#include "RealtimeMediaSource.h"
+#include "RealtimeMediaSourceCenter.h"
+#include "RealtimeMediaSourceSettings.h"
+#include "Timer.h"
+#include <CoreMedia/CMSync.h>
+#include <mach/mach_time.h>
+#include <pal/avfoundation/MediaTimeAVFoundation.h>
+#include <pal/cf/CoreMediaSoftLink.h>
+#include <pal/spi/cf/CoreAudioSPI.h>
+#include <sys/time.h>
+#include <wtf/MainThread.h>
+#include <wtf/NeverDestroyed.h>
+
+namespace WebCore {
+using namespace PAL;
+
+DisplayCaptureSourceCocoa::DisplayCaptureSourceCocoa(const String& name)
+ : RealtimeMediaSource("", Type::Video, name)
+ , m_timer(RunLoop::current(), this, &DisplayCaptureSourceCocoa::emitFrame)
+{
+}
+
+DisplayCaptureSourceCocoa::~DisplayCaptureSourceCocoa()
+{
+#if PLATFORM(IOS)
+ RealtimeMediaSourceCenter::singleton().videoFactory().unsetActiveSource(*this);
+#endif
+}
+
+const RealtimeMediaSourceCapabilities& DisplayCaptureSourceCocoa::capabilities() const
+{
+ if (!m_capabilities) {
+ RealtimeMediaSourceCapabilities capabilities(settings().supportedConstraints());
+
+ // FIXME: what should these be?
+ capabilities.setWidth(CapabilityValueOrRange(72, 2880));
+ capabilities.setHeight(CapabilityValueOrRange(45, 1800));
+ capabilities.setFrameRate(CapabilityValueOrRange(.01, 60.0));
+
+ m_capabilities = WTFMove(capabilities);
+ }
+ return m_capabilities.value();
+}
+
+const RealtimeMediaSourceSettings& DisplayCaptureSourceCocoa::settings() const
+{
+ if (!m_currentSettings) {
+ RealtimeMediaSourceSettings settings;
+ settings.setFrameRate(frameRate());
+ auto size = this->size();
+ if (size.width() && size.height()) {
+ settings.setWidth(size.width());
+ settings.setHeight(size.height());
+ }
+
+ RealtimeMediaSourceSupportedConstraints supportedConstraints;
+ supportedConstraints.setSupportsFrameRate(true);
+ supportedConstraints.setSupportsWidth(true);
+ supportedConstraints.setSupportsHeight(true);
+ supportedConstraints.setSupportsAspectRatio(true);
+ settings.setSupportedConstraints(supportedConstraints);
+
+ m_currentSettings = WTFMove(settings);
+ }
+ return m_currentSettings.value();
+}
+
+void DisplayCaptureSourceCocoa::settingsDidChange()
+{
+ m_currentSettings = std::nullopt;
+ RealtimeMediaSource::settingsDidChange();
+}
+
+void DisplayCaptureSourceCocoa::startProducingData()
+{
+#if PLATFORM(IOS)
+ RealtimeMediaSourceCenter::singleton().videoFactory().setActiveSource(*this);
+#endif
+
+ m_startTime = monotonicallyIncreasingTime();
+ m_timer.startRepeating(1_ms * lround(1000 / frameRate()));
+}
+
+void DisplayCaptureSourceCocoa::stopProducingData()
+{
+ m_timer.stop();
+ m_elapsedTime += monotonicallyIncreasingTime() - m_startTime;
+ m_startTime = NAN;
+}
+
+double DisplayCaptureSourceCocoa::elapsedTime()
+{
+ if (std::isnan(m_startTime))
+ return m_elapsedTime;
+
+ return m_elapsedTime + (monotonicallyIncreasingTime() - m_startTime);
+}
+
+bool DisplayCaptureSourceCocoa::applyFrameRate(double rate)
+{
+ if (m_timer.isActive())
+ m_timer.startRepeating(1_ms * lround(1000 / rate));
+
+ return true;
+}
+
+void DisplayCaptureSourceCocoa::emitFrame()
+{
+ if (muted())
+ return;
+
+ generateFrame();
+}
+
+} // namespace WebCore
+
+#endif // ENABLE(MEDIA_STREAM)
Copied: trunk/Source/WebCore/platform/mediastream/mac/DisplayCaptureSourceCocoa.h (from rev 226411, trunk/Source/WebCore/platform/mock/MockRealtimeMediaSourceCenter.cpp) (0 => 226412)
--- trunk/Source/WebCore/platform/mediastream/mac/DisplayCaptureSourceCocoa.h (rev 0)
+++ trunk/Source/WebCore/platform/mediastream/mac/DisplayCaptureSourceCocoa.h 2018-01-04 20:12:27 UTC (rev 226412)
@@ -0,0 +1,81 @@
+/*
+ * Copyright (C) 2017 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
+
+#if ENABLE(MEDIA_STREAM)
+
+#include "CaptureDevice.h"
+#include "RealtimeMediaSource.h"
+#include <wtf/RefCounted.h>
+#include <wtf/RefPtr.h>
+#include <wtf/RunLoop.h>
+#include <wtf/text/WTFString.h>
+
+namespace WTF {
+class MediaTime;
+}
+
+namespace WebCore {
+
+class CaptureDeviceInfo;
+
+class DisplayCaptureSourceCocoa : public RealtimeMediaSource {
+public:
+
+protected:
+ DisplayCaptureSourceCocoa(const String& name);
+ virtual ~DisplayCaptureSourceCocoa();
+
+ virtual void generateFrame() = 0;
+ void startProducingData() override;
+ void stopProducingData() override;
+
+ double elapsedTime();
+ bool applyFrameRate(double) override;
+
+private:
+
+ bool isCaptureSource() const final { return true; }
+
+ const RealtimeMediaSourceCapabilities& capabilities() const final;
+ const RealtimeMediaSourceSettings& settings() const final;
+ void settingsDidChange() final;
+
+ void emitFrame();
+
+ mutable std::optional<RealtimeMediaSourceCapabilities> m_capabilities;
+ mutable std::optional<RealtimeMediaSourceSettings> m_currentSettings;
+ RealtimeMediaSourceSupportedConstraints m_supportedConstraints;
+
+ double m_startTime { NAN };
+ double m_elapsedTime { 0 };
+
+ RunLoop::Timer<DisplayCaptureSourceCocoa> m_timer;
+};
+
+} // namespace WebCore
+
+#endif // ENABLE(MEDIA_STREAM)
Modified: trunk/Source/WebCore/platform/mediastream/mac/RealtimeMediaSourceCenterMac.cpp (226411 => 226412)
--- trunk/Source/WebCore/platform/mediastream/mac/RealtimeMediaSourceCenterMac.cpp 2018-01-04 18:58:56 UTC (rev 226411)
+++ trunk/Source/WebCore/platform/mediastream/mac/RealtimeMediaSourceCenterMac.cpp 2018-01-04 20:12:27 UTC (rev 226412)
@@ -38,6 +38,7 @@
#include "AVVideoCaptureSource.h"
#include "CoreAudioCaptureDeviceManager.h"
#include "CoreAudioCaptureSource.h"
+#include "DisplayCaptureManagerCocoa.h"
#include "Logging.h"
#include "MediaStreamPrivate.h"
#include <wtf/MainThread.h>
@@ -53,13 +54,12 @@
case CaptureDevice::DeviceType::Camera:
return AVVideoCaptureSource::create(device.persistentId(), constraints);
break;
-
- case CaptureDevice::DeviceType::Microphone:
case CaptureDevice::DeviceType::Screen:
case CaptureDevice::DeviceType::Application:
case CaptureDevice::DeviceType::Window:
case CaptureDevice::DeviceType::Browser:
- case CaptureDevice::DeviceType::Unknown:
+ case CaptureDevice::DeviceType::Microphone:
+ case CaptureDevice::DeviceType::Unknown:
ASSERT_NOT_REACHED();
break;
}
@@ -132,6 +132,11 @@
return AVCaptureDeviceManager::singleton();
}
+CaptureDeviceManager& RealtimeMediaSourceCenterMac::displayCaptureDeviceManager()
+{
+ return DisplayCaptureManagerCocoa::singleton();
+}
+
} // namespace WebCore
#endif // ENABLE(MEDIA_STREAM)
Modified: trunk/Source/WebCore/platform/mediastream/mac/RealtimeMediaSourceCenterMac.h (226411 => 226412)
--- trunk/Source/WebCore/platform/mediastream/mac/RealtimeMediaSourceCenterMac.h 2018-01-04 18:58:56 UTC (rev 226411)
+++ trunk/Source/WebCore/platform/mediastream/mac/RealtimeMediaSourceCenterMac.h 2018-01-04 20:12:27 UTC (rev 226412)
@@ -60,6 +60,7 @@
CaptureDeviceManager& audioCaptureDeviceManager() final;
CaptureDeviceManager& videoCaptureDeviceManager() final;
+ CaptureDeviceManager& displayCaptureDeviceManager() final;
RealtimeMediaSource::AudioCaptureFactory* m_audioFactoryOverride { nullptr };
};
Modified: trunk/Source/WebCore/platform/mock/MockRealtimeMediaSource.cpp (226411 => 226412)
--- trunk/Source/WebCore/platform/mock/MockRealtimeMediaSource.cpp 2018-01-04 18:58:56 UTC (rev 226411)
+++ trunk/Source/WebCore/platform/mock/MockRealtimeMediaSource.cpp 2018-01-04 20:12:27 UTC (rev 226412)
@@ -61,6 +61,9 @@
{ "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;
@@ -123,6 +126,25 @@
return info;
}
+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;
+ }());
+
+ return devices;
+}
+
MockRealtimeMediaSource::MockRealtimeMediaSource(const String& id, RealtimeMediaSource::Type type, const String& name)
: RealtimeMediaSource(id, type, name)
{
Modified: trunk/Source/WebCore/platform/mock/MockRealtimeMediaSource.h (226411 => 226412)
--- trunk/Source/WebCore/platform/mock/MockRealtimeMediaSource.h 2018-01-04 18:58:56 UTC (rev 226411)
+++ trunk/Source/WebCore/platform/mock/MockRealtimeMediaSource.h 2018-01-04 20:12:27 UTC (rev 226412)
@@ -44,10 +44,11 @@
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 };
+ enum class MockDevice { Invalid, Microphone1, Microphone2, Camera1, Camera2, Screen1, Screen2 };
protected:
MockRealtimeMediaSource(const String& id, Type, const String& name);
Modified: trunk/Source/WebCore/platform/mock/MockRealtimeMediaSourceCenter.cpp (226411 => 226412)
--- trunk/Source/WebCore/platform/mock/MockRealtimeMediaSourceCenter.cpp 2018-01-04 18:58:56 UTC (rev 226411)
+++ trunk/Source/WebCore/platform/mock/MockRealtimeMediaSourceCenter.cpp 2018-01-04 20:12:27 UTC (rev 226412)
@@ -30,16 +30,9 @@
#if ENABLE(MEDIA_STREAM)
-#include "CaptureDevice.h"
#include "Logging.h"
-#include "MediaStream.h"
-#include "MediaStreamPrivate.h"
-#include "MediaStreamTrack.h"
#include "MockRealtimeAudioSource.h"
-#include "MockRealtimeMediaSource.h"
#include "MockRealtimeVideoSource.h"
-#include "RealtimeMediaSource.h"
-#include "RealtimeMediaSourceCapabilities.h"
#include <wtf/NeverDestroyed.h>
namespace WebCore {
Modified: trunk/Source/WebCore/platform/mock/MockRealtimeMediaSourceCenter.h (226411 => 226412)
--- trunk/Source/WebCore/platform/mock/MockRealtimeMediaSourceCenter.h 2018-01-04 18:58:56 UTC (rev 226411)
+++ trunk/Source/WebCore/platform/mock/MockRealtimeMediaSourceCenter.h 2018-01-04 20:12:27 UTC (rev 226412)
@@ -51,6 +51,7 @@
CaptureDeviceManager& audioCaptureDeviceManager() final { return m_audioCaptureDeviceManager; }
CaptureDeviceManager& videoCaptureDeviceManager() final { return m_videoCaptureDeviceManager; }
+ CaptureDeviceManager& displayCaptureDeviceManager() final { return m_displayCaptureDeviceManager; }
static std::optional<CaptureDevice> captureDeviceWithPersistentID(CaptureDevice::DeviceType, const String&);
@@ -64,9 +65,15 @@
const Vector<CaptureDevice>& captureDevices() final { return MockRealtimeMediaSource::videoDevices(); }
std::optional<CaptureDevice> captureDeviceWithPersistentID(CaptureDevice::DeviceType type, const String& id) final { return MockRealtimeMediaSource::captureDeviceWithPersistentID(type, id); }
};
+ class MockDisplayCaptureDeviceManager final : public CaptureDeviceManager {
+ private:
+ const Vector<CaptureDevice>& captureDevices() final { return MockRealtimeMediaSource::displayDevices(); }
+ std::optional<CaptureDevice> captureDeviceWithPersistentID(CaptureDevice::DeviceType type, const String& id) final { return MockRealtimeMediaSource::captureDeviceWithPersistentID(type, id); }
+ };
MockAudioCaptureDeviceManager m_audioCaptureDeviceManager;
MockVideoCaptureDeviceManager m_videoCaptureDeviceManager;
+ MockDisplayCaptureDeviceManager m_displayCaptureDeviceManager;
};
}
Modified: trunk/Source/WebCore/platform/mock/MockRealtimeVideoSource.cpp (226411 => 226412)
--- trunk/Source/WebCore/platform/mock/MockRealtimeVideoSource.cpp 2018-01-04 18:58:56 UTC (rev 226411)
+++ trunk/Source/WebCore/platform/mock/MockRealtimeVideoSource.cpp 2018-01-04 20:12:27 UTC (rev 226412)
@@ -58,10 +58,9 @@
switch (device.type()) {
case CaptureDevice::DeviceType::Camera:
+ case CaptureDevice::DeviceType::Screen:
return MockRealtimeVideoSource::create(device.persistentId(), device.label(), constraints);
break;
-
- case CaptureDevice::DeviceType::Screen:
case CaptureDevice::DeviceType::Application:
case CaptureDevice::DeviceType::Window:
case CaptureDevice::DeviceType::Browser:
@@ -119,6 +118,12 @@
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:
@@ -170,7 +175,12 @@
void MockRealtimeVideoSource::updateSettings(RealtimeMediaSourceSettings& settings)
{
- settings.setFacingMode(facingMode());
+ if (mockCamera())
+ settings.setFacingMode(facingMode());
+ else {
+ settings.setDisplaySurface(RealtimeMediaSourceSettings::DisplaySurfaceType::Monitor);
+ settings.setLogicalSurface(true);
+ }
settings.setFrameRate(frameRate());
IntSize size = this->size();
settings.setWidth(size.width());
@@ -181,15 +191,21 @@
void MockRealtimeVideoSource::initializeCapabilities(RealtimeMediaSourceCapabilities& capabilities)
{
- if (device() == MockDevice::Camera1)
- capabilities.addFacingMode(RealtimeMediaSourceSettings::User);
- else
- capabilities.addFacingMode(RealtimeMediaSourceSettings::Environment);
+ if (mockCamera()) {
+ if (device() == MockDevice::Camera1)
+ capabilities.addFacingMode(RealtimeMediaSourceSettings::User);
+ else
+ capabilities.addFacingMode(RealtimeMediaSourceSettings::Environment);
- capabilities.setWidth(CapabilityValueOrRange(320, 1920));
- capabilities.setHeight(CapabilityValueOrRange(240, 1080));
- capabilities.setFrameRate(CapabilityValueOrRange(15.0, 60.0));
- capabilities.setAspectRatio(CapabilityValueOrRange(4 / 3.0, 16 / 9.0));
+ capabilities.setWidth(CapabilityValueOrRange(320, 1920));
+ capabilities.setHeight(CapabilityValueOrRange(240, 1080));
+ capabilities.setFrameRate(CapabilityValueOrRange(15.0, 60.0));
+ capabilities.setAspectRatio(CapabilityValueOrRange(4 / 3.0, 16 / 9.0));
+ } else {
+ capabilities.setWidth(CapabilityValueOrRange(72, 2880));
+ capabilities.setHeight(CapabilityValueOrRange(45, 1800));
+ capabilities.setFrameRate(CapabilityValueOrRange(.01, 60.0));
+ }
}
void MockRealtimeVideoSource::initializeSupportedConstraints(RealtimeMediaSourceSupportedConstraints& supportedConstraints)
@@ -198,7 +214,8 @@
supportedConstraints.setSupportsHeight(true);
supportedConstraints.setSupportsAspectRatio(true);
supportedConstraints.setSupportsFrameRate(true);
- supportedConstraints.setSupportsFacingMode(true);
+ if (mockCamera())
+ supportedConstraints.setSupportsFacingMode(true);
}
bool MockRealtimeVideoSource::applyFrameRate(double rate)
@@ -352,27 +369,32 @@
statsLocation.move(0, m_statsFontSize);
context.drawText(statsFont, TextRun((StringView(string))), statsLocation);
- const char* camera;
- switch (facingMode()) {
- case RealtimeMediaSourceSettings::User:
- camera = "User facing";
- break;
- case RealtimeMediaSourceSettings::Environment:
- camera = "Environment facing";
- break;
- case RealtimeMediaSourceSettings::Left:
- camera = "Left facing";
- break;
- case RealtimeMediaSourceSettings::Right:
- camera = "Right facing";
- break;
- case RealtimeMediaSourceSettings::Unknown:
- camera = "Unknown";
- break;
+ if (mockCamera()) {
+ const char* camera;
+ switch (facingMode()) {
+ case RealtimeMediaSourceSettings::User:
+ camera = "User facing";
+ break;
+ case RealtimeMediaSourceSettings::Environment:
+ camera = "Environment facing";
+ break;
+ case RealtimeMediaSourceSettings::Left:
+ camera = "Left facing";
+ break;
+ case RealtimeMediaSourceSettings::Right:
+ camera = "Right facing";
+ break;
+ case RealtimeMediaSourceSettings::Unknown:
+ camera = "Unknown";
+ break;
+ }
+ string = String::format("Camera: %s", camera);
+ statsLocation.move(0, m_statsFontSize);
+ 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);
}
- string = String::format("Camera: %s", camera);
- statsLocation.move(0, m_statsFontSize);
- context.drawText(statsFont, TextRun((StringView(string))), statsLocation);
FloatPoint bipBopLocation(size.width() * .6, size.height() * .6);
unsigned frameMod = m_frameNumber % 60;
@@ -418,6 +440,12 @@
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:
Modified: trunk/Source/WebCore/platform/mock/MockRealtimeVideoSource.h (226411 => 226412)
--- trunk/Source/WebCore/platform/mock/MockRealtimeVideoSource.h 2018-01-04 18:58:56 UTC (rev 226411)
+++ trunk/Source/WebCore/platform/mock/MockRealtimeVideoSource.h 2018-01-04 20:12:27 UTC (rev 226412)
@@ -83,6 +83,9 @@
void delaySamples(float) override;
+ bool mockCamera() const { return device() == MockDevice::Camera1 || device() == MockDevice::Camera2; }
+ bool mockScreen() const { return device() == MockDevice::Screen1 || device() == MockDevice::Screen2; }
+
float m_baseFontSize { 0 };
float m_bipBopFontSize { 0 };
float m_statsFontSize { 0 };
Modified: trunk/Source/WebKit/ChangeLog (226411 => 226412)
--- trunk/Source/WebKit/ChangeLog 2018-01-04 18:58:56 UTC (rev 226411)
+++ trunk/Source/WebKit/ChangeLog 2018-01-04 20:12:27 UTC (rev 226412)
@@ -1,3 +1,37 @@
+2018-01-04 Eric Carlson <[email protected]>
+
+ [MediaStream] Add Mock screen capture source
+ https://bugs.webkit.org/show_bug.cgi?id=181291
+ <rdar://problem/36298164>
+
+ Reviewed by Dean Jackson.
+
+ * Shared/WebCoreArgumentCoders.cpp:
+ (IPC::ArgumentCoder<MediaConstraints>::decode):
+ (IPC::ArgumentCoder<CaptureDevice>::encode): Deleted, moved to CaptureDevice.h
+ (IPC::ArgumentCoder<CaptureDevice>::decode): Ditto.
+ * Shared/WebCoreArgumentCoders.h:
+
+ * UIProcess/API/Cocoa/WKWebViewPrivate.h: Add _WKCaptureDeviceDisplay.
+ * UIProcess/Cocoa/UIDelegate.mm:
+ (WebKit::requestUserMediaAuthorizationForDevices): Deal with display capture.
+ (WebKit::UIDelegate::UIClient::decidePolicyForUserMediaPermissionRequest): Ditto.
+
+ * UIProcess/UserMediaPermissionRequestManagerProxy.cpp:
+ (WebKit::UserMediaPermissionRequestManagerProxy::userMediaAccessWasDenied): requiresAudio -> requiresAudioCapture.
+ (WebKit::UserMediaPermissionRequestManagerProxy::searchForGrantedRequest const): Never reuse
+ a previously granted display capture request.
+
+ * UIProcess/UserMediaPermissionRequestProxy.cpp:
+ (WebKit::UserMediaPermissionRequestProxy::allow): Search the eligible devices instead of asking
+ the source center to find devices.
+ * UIProcess/UserMediaPermissionRequestProxy.h:
+ (WebKit::UserMediaPermissionRequestProxy::requiresAudioCapture const): Renamed.
+ (WebKit::UserMediaPermissionRequestProxy::requiresVideoCapture const): Ditto.
+ (WebKit::UserMediaPermissionRequestProxy::requiresDisplayCapture const): New.
+ (WebKit::UserMediaPermissionRequestProxy::requiresAudio const): Deleted.
+ (WebKit::UserMediaPermissionRequestProxy::requiresVideo const): Deleted.
+
2018-01-04 Youenn Fablet <[email protected]>
FetchResponse should set its internal response text encoding name
Modified: trunk/Source/WebKit/Shared/WebCoreArgumentCoders.cpp (226411 => 226412)
--- trunk/Source/WebKit/Shared/WebCoreArgumentCoders.cpp 2018-01-04 18:58:56 UTC (rev 226411)
+++ trunk/Source/WebKit/Shared/WebCoreArgumentCoders.cpp 2018-01-04 20:12:27 UTC (rev 226412)
@@ -2598,47 +2598,6 @@
&& decoder.decode(constraints.deviceIDHashSalt)
&& decoder.decode(constraints.isValid);
}
-
-void ArgumentCoder<CaptureDevice>::encode(Encoder& encoder, const WebCore::CaptureDevice& device)
-{
- encoder << device.persistentId();
- encoder << device.label();
- encoder << device.groupId();
- encoder << device.enabled();
- encoder.encodeEnum(device.type());
-}
-
-std::optional<CaptureDevice> ArgumentCoder<CaptureDevice>::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<String> groupId;
- decoder >> groupId;
- if (!groupId)
- return std::nullopt;
-
- std::optional<bool> enabled;
- decoder >> enabled;
- if (!enabled)
- return std::nullopt;
-
- std::optional<CaptureDevice::DeviceType> type;
- decoder >> type;
- if (!type)
- return std::nullopt;
-
- std::optional<CaptureDevice> device = {{ WTFMove(*persistentId), WTFMove(*type), WTFMove(*label), WTFMove(*groupId) }};
- device->setEnabled(*enabled);
- return device;
-}
#endif
#if ENABLE(INDEXED_DATABASE)
Modified: trunk/Source/WebKit/Shared/WebCoreArgumentCoders.h (226411 => 226412)
--- trunk/Source/WebKit/Shared/WebCoreArgumentCoders.h 2018-01-04 18:58:56 UTC (rev 226411)
+++ trunk/Source/WebKit/Shared/WebCoreArgumentCoders.h 2018-01-04 20:12:27 UTC (rev 226412)
@@ -28,7 +28,6 @@
#include "ArgumentCoders.h"
#include <WebCore/AutoplayEvent.h>
#include <WebCore/CacheStorageConnection.h>
-#include <WebCore/CaptureDevice.h>
#include <WebCore/ColorSpace.h>
#include <WebCore/DiagnosticLoggingClient.h>
#include <WebCore/FrameLoaderTypes.h>
@@ -152,7 +151,6 @@
#endif
#if ENABLE(MEDIA_STREAM)
-class CaptureDevice;
struct MediaConstraints;
#endif
@@ -648,11 +646,6 @@
static void encode(Encoder&, const WebCore::MediaConstraints&);
static bool decode(Decoder&, WebCore::MediaConstraints&);
};
-
-template<> struct ArgumentCoder<WebCore::CaptureDevice> {
- static void encode(Encoder&, const WebCore::CaptureDevice&);
- static std::optional<WebCore::CaptureDevice> decode(Decoder&);
-};
#endif
#if ENABLE(INDEXED_DATABASE)
@@ -770,14 +763,6 @@
#endif
#if ENABLE(MEDIA_STREAM)
-template<> struct EnumTraits<WebCore::CaptureDevice::DeviceType> {
- using values = EnumValues<
- WebCore::CaptureDevice::DeviceType,
- WebCore::CaptureDevice::DeviceType::Unknown,
- WebCore::CaptureDevice::DeviceType::Microphone,
- WebCore::CaptureDevice::DeviceType::Camera
- >;
-};
template<> struct EnumTraits<WebCore::RealtimeMediaSource::Type> {
using values = EnumValues<
WebCore::RealtimeMediaSource::Type,
Modified: trunk/Source/WebKit/UIProcess/API/Cocoa/WKWebViewPrivate.h (226411 => 226412)
--- trunk/Source/WebKit/UIProcess/API/Cocoa/WKWebViewPrivate.h 2018-01-04 18:58:56 UTC (rev 226411)
+++ trunk/Source/WebKit/UIProcess/API/Cocoa/WKWebViewPrivate.h 2018-01-04 20:12:27 UTC (rev 226412)
@@ -59,6 +59,7 @@
typedef NS_OPTIONS(NSUInteger, _WKCaptureDevices) {
_WKCaptureDeviceMicrophone = 1 << 0,
_WKCaptureDeviceCamera = 1 << 1,
+ _WKCaptureDeviceDisplay = 1 << 2,
} WK_API_AVAILABLE(macosx(10.13), ios(11.0));
#if TARGET_OS_IPHONE
Modified: trunk/Source/WebKit/UIProcess/Cocoa/UIDelegate.mm (226411 => 226412)
--- trunk/Source/WebKit/UIProcess/Cocoa/UIDelegate.mm 2018-01-04 18:58:56 UTC (rev 226411)
+++ trunk/Source/WebKit/UIProcess/Cocoa/UIDelegate.mm 2018-01-04 20:12:27 UTC (rev 226412)
@@ -793,8 +793,8 @@
protectedRequest->deny(UserMediaPermissionRequestProxy::UserMediaAccessDenialReason::PermissionDenied);
return;
}
- const String& videoDeviceUID = protectedRequest->requiresVideo() ? protectedRequest->videoDeviceUIDs().first() : String();
- const String& audioDeviceUID = protectedRequest->requiresAudio() ? protectedRequest->audioDeviceUIDs().first() : String();
+ const String& videoDeviceUID = (protectedRequest->requiresVideoCapture() || protectedRequest->requiresDisplayCapture()) ? protectedRequest->videoDeviceUIDs().first() : String();
+ const String& audioDeviceUID = protectedRequest->requiresAudioCapture() ? protectedRequest->audioDeviceUIDs().first() : String();
protectedRequest->allow(audioDeviceUID, videoDeviceUID);
});
@@ -803,10 +803,14 @@
WebCore::URL mainFrameURL(WebCore::URL(), mainFrame->url());
_WKCaptureDevices devices = 0;
- if (request.requiresAudio())
+ if (request.requiresAudioCapture())
devices |= _WKCaptureDeviceMicrophone;
- if (request.requiresVideo())
+ if (request.requiresVideoCapture())
devices |= _WKCaptureDeviceCamera;
+ if (request.requiresDisplayCapture()) {
+ devices |= _WKCaptureDeviceDisplay;
+ ASSERT(!(devices & _WKCaptureDeviceCamera));
+ }
auto protectedWebView = RetainPtr<WKWebView>(&webView);
[delegate _webView:protectedWebView.get() requestUserMediaAuthorizationForDevices:devices url:requestFrameURL mainFrameURL:mainFrameURL decisionHandler:decisionHandler.get()];
@@ -820,9 +824,10 @@
return true;
}
- bool requiresAudio = request.requiresAudio();
- bool requiresVideo = request.requiresVideo();
- if (!requiresAudio && !requiresVideo) {
+ bool requiresAudioCapture = request.requiresAudioCapture();
+ bool requiresVideoCapture = request.requiresVideoCapture();
+ bool requiresDisplayCapture = request.requiresDisplayCapture();
+ if (!requiresAudioCapture && !requiresVideoCapture && !requiresDisplayCapture) {
request.deny(UserMediaPermissionRequestProxy::UserMediaAccessDenialReason::NoConstraints);
return true;
}
@@ -830,7 +835,7 @@
#if PLATFORM(IOS)
auto requestCameraAuthorization = BlockPtr<void()>::fromCallable([this, &frame, protectedRequest = makeRef(request), webView = RetainPtr<WKWebView>(m_uiDelegate.m_webView)]() {
- if (!protectedRequest->requiresVideo()) {
+ if (!protectedRequest->requiresVideoCapture()) {
requestUserMediaAuthorizationForDevices(frame, protectedRequest, (id <WKUIDelegatePrivate>)m_uiDelegate.m_delegate.get(), *webView.get());
return;
}
@@ -857,7 +862,7 @@
}
});
- if (requiresAudio) {
+ if (requiresAudioCapture) {
AVAuthorizationStatus microphoneAuthorizationStatus = [getAVCaptureDeviceClass() authorizationStatusForMediaType:getAVMediaTypeAudio()];
switch (microphoneAuthorizationStatus) {
case AVAuthorizationStatusAuthorized:
Modified: trunk/Source/WebKit/UIProcess/UserMediaPermissionRequestManagerProxy.cpp (226411 => 226412)
--- trunk/Source/WebKit/UIProcess/UserMediaPermissionRequestManagerProxy.cpp 2018-01-04 18:58:56 UTC (rev 226411)
+++ trunk/Source/WebKit/UIProcess/UserMediaPermissionRequestManagerProxy.cpp 2018-01-04 20:12:27 UTC (rev 226412)
@@ -122,7 +122,7 @@
return;
if (reason == UserMediaPermissionRequestProxy::UserMediaAccessDenialReason::PermissionDenied)
- m_deniedRequests.append(DeniedRequest { request->mainFrameID(), request->userMediaDocumentSecurityOrigin(), request->topLevelDocumentSecurityOrigin(), request->requiresAudio(), request->requiresVideo() });
+ m_deniedRequests.append(DeniedRequest { request->mainFrameID(), request->userMediaDocumentSecurityOrigin(), request->topLevelDocumentSecurityOrigin(), request->requiresAudioCapture(), request->requiresVideoCapture() });
denyRequest(userMediaID, reason, emptyString());
}
@@ -178,6 +178,8 @@
bool checkForAudio = needsAudio;
bool checkForVideo = needsVideo;
for (const auto& grantedRequest : m_grantedRequests) {
+ if (grantedRequest->requiresDisplayCapture())
+ continue;
if (!grantedRequest->userMediaDocumentSecurityOrigin().isSameSchemeHostPort(userMediaDocumentOrigin))
continue;
if (!grantedRequest->topLevelDocumentSecurityOrigin().isSameSchemeHostPort(topLevelDocumentOrigin))
@@ -185,10 +187,10 @@
if (grantedRequest->frameID() != frameID)
continue;
- if (grantedRequest->requiresVideo())
+ if (grantedRequest->requiresVideoCapture())
checkForVideo = false;
- if (grantedRequest->requiresAudio())
+ if (grantedRequest->requiresAudioCapture())
checkForAudio = false;
if (checkForVideo || checkForAudio)
Modified: trunk/Source/WebKit/UIProcess/UserMediaPermissionRequestProxy.cpp (226411 => 226412)
--- trunk/Source/WebKit/UIProcess/UserMediaPermissionRequestProxy.cpp 2018-01-04 18:58:56 UTC (rev 226411)
+++ trunk/Source/WebKit/UIProcess/UserMediaPermissionRequestProxy.cpp 2018-01-04 20:12:27 UTC (rev 226412)
@@ -52,23 +52,30 @@
return;
#if ENABLE(MEDIA_STREAM)
-
- auto& sourceCenter = RealtimeMediaSourceCenter::singleton();
CaptureDevice audioDevice;
if (!audioDeviceUID.isEmpty()) {
- auto device = sourceCenter.captureDeviceWithPersistentID(WebCore::CaptureDevice::DeviceType::Microphone, audioDeviceUID);
- ASSERT(device && device.value().enabled());
- if (device)
- audioDevice = device.value();
+ size_t index = m_eligibleAudioDevices.findMatching([&](const auto& device) {
+ return device.persistentId() == audioDeviceUID;
+ });
+ ASSERT(index != notFound);
+
+ if (index != notFound)
+ audioDevice = m_eligibleAudioDevices[index];
+
+ ASSERT(audioDevice.enabled());
}
CaptureDevice videoDevice;
if (!videoDeviceUID.isEmpty()) {
- auto device = sourceCenter.captureDeviceWithPersistentID(WebCore::CaptureDevice::DeviceType::Camera, videoDeviceUID);
+ size_t index = m_eligibleVideoDevices.findMatching([&](const auto& device) {
+ return device.persistentId() == videoDeviceUID;
+ });
+ ASSERT(index != notFound);
- ASSERT(device && device.value().enabled());
- if (device)
- videoDevice = device.value();
+ if (index != notFound)
+ videoDevice = m_eligibleVideoDevices[index];
+
+ ASSERT(videoDevice.enabled());
}
m_manager->userMediaAccessWasGranted(m_userMediaID, WTFMove(audioDevice), WTFMove(videoDevice));
Modified: trunk/Source/WebKit/UIProcess/UserMediaPermissionRequestProxy.h (226411 => 226412)
--- trunk/Source/WebKit/UIProcess/UserMediaPermissionRequestProxy.h 2018-01-04 18:58:56 UTC (rev 226411)
+++ trunk/Source/WebKit/UIProcess/UserMediaPermissionRequestProxy.h 2018-01-04 20:12:27 UTC (rev 226412)
@@ -49,8 +49,9 @@
void invalidate();
- bool requiresAudio() const { return m_eligibleAudioDevices.size(); }
- bool requiresVideo() const { return m_eligibleVideoDevices.size(); }
+ bool requiresAudioCapture() const { return m_eligibleAudioDevices.size(); }
+ bool requiresVideoCapture() const { return !requiresDisplayCapture() && m_eligibleVideoDevices.size(); }
+ bool requiresDisplayCapture() const { return m_request.type == WebCore::MediaStreamRequest::Type::DisplayMedia && m_eligibleVideoDevices.size(); }
Vector<String> videoDeviceUIDs() const;
Vector<String> audioDeviceUIDs() const;
Modified: trunk/Tools/ChangeLog (226411 => 226412)
--- trunk/Tools/ChangeLog 2018-01-04 18:58:56 UTC (rev 226411)
+++ trunk/Tools/ChangeLog 2018-01-04 20:12:27 UTC (rev 226412)
@@ -1,3 +1,15 @@
+2018-01-04 Eric Carlson <[email protected]>
+
+ [MediaStream] Add Mock screen capture source
+ https://bugs.webkit.org/show_bug.cgi?id=181291
+ <rdar://problem/36298164>
+
+ Reviewed by Dean Jackson.
+
+ * TestWebKitAPI/TestWebKitAPI.xcodeproj/project.pbxproj: Add new test.
+ * TestWebKitAPI/Tests/WebKitCocoa/GetDisplayMedia.mm:
+ * TestWebKitAPI/Tests/WebKit/getDisplayMedia.html:
+
2018-01-04 Lucas Forschler <[email protected]>
<rdar://problem/36300930> Change proxy server setting on master config to reach s3 servers
Modified: trunk/Tools/TestWebKitAPI/TestWebKitAPI.xcodeproj/project.pbxproj (226411 => 226412)
--- trunk/Tools/TestWebKitAPI/TestWebKitAPI.xcodeproj/project.pbxproj 2018-01-04 18:58:56 UTC (rev 226411)
+++ trunk/Tools/TestWebKitAPI/TestWebKitAPI.xcodeproj/project.pbxproj 2018-01-04 20:12:27 UTC (rev 226412)
@@ -30,6 +30,8 @@
0799C34B1EBA3301003B7532 /* disableGetUserMedia.html in Copy Resources */ = {isa = PBXBuildFile; fileRef = 0799C34A1EBA32F4003B7532 /* disableGetUserMedia.html */; };
07C046CA1E4262A8007201E7 /* CARingBuffer.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 07C046C91E42573E007201E7 /* CARingBuffer.cpp */; };
07CE1CF31F06A7E000BF89F5 /* GetUserMediaNavigation.mm in Sources */ = {isa = PBXBuildFile; fileRef = 07CE1CF21F06A7E000BF89F5 /* GetUserMediaNavigation.mm */; };
+ 07E1F6A21FFC44FA0096C7EC /* getDisplayMedia.html in Copy Resources */ = {isa = PBXBuildFile; fileRef = 07E1F6A11FFC44F90096C7EC /* getDisplayMedia.html */; };
+ 07E1F6A31FFC4B760096C7EC /* GetDisplayMedia.mm in Sources */ = {isa = PBXBuildFile; fileRef = 07E1F6A01FFC3A080096C7EC /* GetDisplayMedia.mm */; };
07E499911F9E56DF002F1EF3 /* GetUserMediaReprompt.mm in Sources */ = {isa = PBXBuildFile; fileRef = 07E499901F9E56A1002F1EF3 /* GetUserMediaReprompt.mm */; };
0F139E771A423A5B00F590F5 /* WeakObjCPtr.mm in Sources */ = {isa = PBXBuildFile; fileRef = 0F139E751A423A5300F590F5 /* WeakObjCPtr.mm */; };
0F139E781A423A6B00F590F5 /* PlatformUtilitiesCocoa.mm in Sources */ = {isa = PBXBuildFile; fileRef = 0F139E721A423A2B00F590F5 /* PlatformUtilitiesCocoa.mm */; };
@@ -924,6 +926,7 @@
26F52EAF18288C230023D412 /* geolocationGetCurrentPositionWithHighAccuracy.html in Copy Resources */,
26F52EB218288F240023D412 /* geolocationWatchPosition.html in Copy Resources */,
26F52EB318288F240023D412 /* geolocationWatchPositionWithHighAccuracy.html in Copy Resources */,
+ 07E1F6A21FFC44FA0096C7EC /* getDisplayMedia.html in Copy Resources */,
074994421EA5034B000DA44E /* getUserMedia.html in Copy Resources */,
F46A095B1ED8A6E600D4AA55 /* gif-and-file-input.html in Copy Resources */,
9B4F8FA7159D52DD002D9F94 /* HTMLCollectionNamedItem.html in Copy Resources */,
@@ -1083,6 +1086,8 @@
0799C34A1EBA32F4003B7532 /* disableGetUserMedia.html */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.html; path = disableGetUserMedia.html; sourceTree = "<group>"; };
07C046C91E42573E007201E7 /* CARingBuffer.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = CARingBuffer.cpp; sourceTree = "<group>"; };
07CE1CF21F06A7E000BF89F5 /* GetUserMediaNavigation.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = GetUserMediaNavigation.mm; sourceTree = "<group>"; };
+ 07E1F6A01FFC3A080096C7EC /* GetDisplayMedia.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = GetDisplayMedia.mm; sourceTree = "<group>"; };
+ 07E1F6A11FFC44F90096C7EC /* getDisplayMedia.html */ = {isa = PBXFileReference; lastKnownFileType = text.html; name = getDisplayMedia.html; path = ../WebKit/getDisplayMedia.html; sourceTree = "<group>"; };
07E499901F9E56A1002F1EF3 /* GetUserMediaReprompt.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = GetUserMediaReprompt.mm; sourceTree = "<group>"; };
07EDEFAC1EB9400C00D43292 /* UserMediaDisabled.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = UserMediaDisabled.mm; sourceTree = "<group>"; };
0BCD833414857CE400EA2003 /* HashMap.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = HashMap.cpp; sourceTree = "<group>"; };
@@ -2068,6 +2073,7 @@
3F1B52681D3D7129008D60C4 /* FullscreenLayoutConstraints.mm */,
CDE195B31CFE0ADE0053D256 /* FullscreenTopContentInset.mm */,
631EFFF51E7B5E8D00D2EBB8 /* Geolocation.mm */,
+ 07E1F6A01FFC3A080096C7EC /* GetDisplayMedia.mm */,
51AF23DE1EF1A3720072F281 /* IconLoadingDelegate.mm */,
510477751D298E03009747EB /* IDBDeleteRecovery.mm */,
5110FCEF1E01CBAA006F8D0B /* IDBIndexUpgradeToV2.mm */,
@@ -2348,6 +2354,7 @@
3FBD1B491D39D1DB00E6D6FA /* FullscreenLayoutConstraints.html */,
CDE195B21CFE0ADE0053D256 /* FullscreenTopContentInset.html */,
636353A61E9861940009F8AF /* GeolocationGetCurrentPositionResult.html */,
+ 07E1F6A11FFC44F90096C7EC /* getDisplayMedia.html */,
F47D30ED1ED28A6C000482E1 /* gif-and-file-input.html */,
510477761D298E57009747EB /* IDBDeleteRecovery.html */,
5104776F1D298D85009747EB /* IDBDeleteRecovery.sqlite3 */,
@@ -3412,6 +3419,7 @@
7CCE7EF81A411AE600447C4C /* Geolocation.cpp in Sources */,
631EFFF61E7B5E8D00D2EBB8 /* Geolocation.mm in Sources */,
7CCE7EE11A411A9A00447C4C /* GetBackingScaleFactor.mm in Sources */,
+ 07E1F6A31FFC4B760096C7EC /* GetDisplayMedia.mm in Sources */,
7CCE7EF91A411AE600447C4C /* GetInjectedBundleInitializationUserDataCallback.cpp in Sources */,
7CCE7EE21A411A9A00447C4C /* GetPIDAfterAbortedProcessLaunch.cpp in Sources */,
07CE1CF31F06A7E000BF89F5 /* GetUserMediaNavigation.mm in Sources */,
Added: trunk/Tools/TestWebKitAPI/Tests/WebKit/getDisplayMedia.html (0 => 226412)
--- trunk/Tools/TestWebKitAPI/Tests/WebKit/getDisplayMedia.html (rev 0)
+++ trunk/Tools/TestWebKitAPI/Tests/WebKit/getDisplayMedia.html 2018-01-04 20:12:27 UTC (rev 226412)
@@ -0,0 +1,55 @@
+<!DOCTYPE html>
+<html>
+ <head>
+ <script>
+
+ let stream = null;
+
+ function promptForCapture(constraints)
+ {
+ navigator.mediaDevices.getDisplayMedia(constraints)
+ .then((s) => {
+ stream = s;
+ video.srcObject = stream;
+ if (window.webkit)
+ window.webkit.messageHandlers.testHandler.postMessage('allowed');
+ })
+ .catch((error) => {
+ if (window.webkit)
+ window.webkit.messageHandlers.testHandler.postMessage('denied');
+ });
+ }
+
+ function stop(kind)
+ {
+ if (!stream)
+ return;
+
+ let activeTracks = [];
+ stream.getTracks().forEach(track => {
+ if (!kind || track.kind == kind)
+ track.stop();
+ else
+ activeTracks.push(track);
+ });
+
+ if (!activeTracks.length) {
+ stream = null;
+ video.srcObject = null;
+ }
+ }
+
+ function haveStream()
+ {
+ return stream !== null;
+ }
+ </script>
+ <head>
+
+ <body>
+ <video id="video" controls></video>
+ <p>
+ <button _onclick_="stop()">Stop</button>
+ </p>
+ </body>
+</html>
Added: trunk/Tools/TestWebKitAPI/Tests/WebKitCocoa/GetDisplayMedia.mm (0 => 226412)
--- trunk/Tools/TestWebKitAPI/Tests/WebKitCocoa/GetDisplayMedia.mm (rev 0)
+++ trunk/Tools/TestWebKitAPI/Tests/WebKitCocoa/GetDisplayMedia.mm 2018-01-04 20:12:27 UTC (rev 226412)
@@ -0,0 +1,171 @@
+/*
+ * Copyright (C) 2017 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. AND ITS 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 APPLE INC. OR ITS 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.
+ */
+
+#import "config.h"
+
+#if WK_API_ENABLED
+
+#if ENABLE(MEDIA_STREAM)
+
+#import "PlatformUtilities.h"
+#import "Test.h"
+#import "TestWKWebView.h"
+#import <WebKit/WKPreferencesPrivate.h>
+#import <WebKit/WKUIDelegatePrivate.h>
+#import <WebKit/WKWebView.h>
+#import <WebKit/WKWebViewConfiguration.h>
+
+static bool wasPrompted = false;
+static _WKCaptureDevices requestedDevices = 0;
+static bool receivedScriptMessage = false;
+static RetainPtr<WKScriptMessage> lastScriptMessage;
+
+@interface GetDisplayMediaMessageHandler : NSObject <WKScriptMessageHandler>
+@end
+
+@implementation GetDisplayMediaMessageHandler
+
+- (void)userContentController:(WKUserContentController *)userContentController didReceiveScriptMessage:(WKScriptMessage *)message
+{
+ lastScriptMessage = message;
+ receivedScriptMessage = true;
+}
+@end
+
+@interface GetDisplayMediaUIDelegate : NSObject<WKUIDelegate>
+- (void)_webView:(WKWebView *)webView requestUserMediaAuthorizationForDevices:(_WKCaptureDevices)devices url:(NSURL *)url mainFrameURL:(NSURL *)mainFrameURL decisionHandler:(void (^)(BOOL authorized))decisionHandler;
+- (void)_webView:(WKWebView *)webView checkUserMediaPermissionForURL:(NSURL *)url mainFrameURL:(NSURL *)mainFrameURL frameIdentifier:(NSUInteger)frameIdentifier decisionHandler:(void (^)(NSString *salt, BOOL authorized))decisionHandler;
+@end
+
+@implementation GetDisplayMediaUIDelegate
+- (void)_webView:(WKWebView *)webView requestUserMediaAuthorizationForDevices:(_WKCaptureDevices)devices url:(NSURL *)url mainFrameURL:(NSURL *)mainFrameURL decisionHandler:(void (^)(BOOL authorized))decisionHandler
+{
+ wasPrompted = true;
+
+ requestedDevices = devices;
+ BOOL needsMicrophoneAuthorization = !!(requestedDevices & _WKCaptureDeviceMicrophone);
+ BOOL needsCameraAuthorization = !!(requestedDevices & _WKCaptureDeviceCamera);
+ BOOL needsDisplayCaptureAuthorization = !!(requestedDevices & _WKCaptureDeviceDisplay);
+ if (!needsMicrophoneAuthorization && !needsCameraAuthorization && !needsDisplayCaptureAuthorization) {
+ decisionHandler(NO);
+ return;
+ }
+
+ decisionHandler(YES);
+}
+
+- (void)_webView:(WKWebView *)webView checkUserMediaPermissionForURL:(NSURL *)url mainFrameURL:(NSURL *)mainFrameURL frameIdentifier:(NSUInteger)frameIdentifier decisionHandler:(void (^)(NSString *salt, BOOL authorized))decisionHandler
+{
+ decisionHandler(@"0x987654321", YES);
+}
+@end
+
+namespace TestWebKitAPI {
+
+class GetDisplayMediaTest : public testing::Test {
+public:
+ virtual void SetUp()
+ {
+ m_configuration = adoptNS([[WKWebViewConfiguration alloc] init]);
+
+ auto handler = adoptNS([[GetDisplayMediaMessageHandler alloc] init]);
+ [[m_configuration userContentController] addScriptMessageHandler:handler.get() name:@"testHandler"];
+
+ auto preferences = [m_configuration preferences];
+ preferences._mediaCaptureRequiresSecureConnection = NO;
+ preferences._mediaDevicesEnabled = YES;
+ preferences._mockCaptureDevicesEnabled = YES;
+ preferences._screenCaptureEnabled = YES;
+
+ m_webView = adoptNS([[TestWKWebView alloc] initWithFrame:NSMakeRect(0, 0, 800, 600) configuration:m_configuration.get()]);
+
+ m_uiDelegate = adoptNS([[GetDisplayMediaUIDelegate alloc] init]);
+ m_webView.get().UIDelegate = m_uiDelegate.get();
+
+ [m_webView synchronouslyLoadTestPageNamed:@"getDisplayMedia"];
+ }
+
+ bool haveStream(bool expected)
+ {
+ int retryCount = 10;
+ while (retryCount--) {
+ auto result = [m_webView stringByEvaluatingJavaScript:@"haveStream()"];
+ if (result.boolValue == expected)
+ return YES;
+
+ TestWebKitAPI::Util::spinRunLoop(10);
+ }
+
+ return NO;
+ }
+
+ void promptForCapture(NSString* constraints, bool shouldSucceed)
+ {
+ [m_webView stringByEvaluatingJavaScript:@"stop()"];
+ EXPECT_TRUE(haveStream(false));
+
+ wasPrompted = false;
+ receivedScriptMessage = false;
+
+ NSString *script = [NSString stringWithFormat:@"promptForCapture(%@)", constraints];
+ [m_webView stringByEvaluatingJavaScript:script];
+
+ TestWebKitAPI::Util::run(&receivedScriptMessage);
+ if (shouldSucceed) {
+ EXPECT_STREQ([(NSString *)[lastScriptMessage body] UTF8String], "allowed");
+ EXPECT_TRUE(haveStream(true));
+ EXPECT_TRUE(wasPrompted);
+ } else {
+ EXPECT_STREQ([(NSString *)[lastScriptMessage body] UTF8String], "denied");
+ EXPECT_TRUE(haveStream(false));
+ EXPECT_FALSE(wasPrompted);
+ }
+ }
+
+ RetainPtr<WKWebViewConfiguration> m_configuration;
+ RetainPtr<GetDisplayMediaUIDelegate> m_uiDelegate;
+ RetainPtr<TestWKWebView> m_webView;
+};
+
+TEST_F(GetDisplayMediaTest, BasicPrompt)
+{
+ promptForCapture(@"{ audio: true, video: true }", true);
+ promptForCapture(@"{ audio: true, video: false }", true);
+ promptForCapture(@"{ audio: false, video: true }", true);
+ promptForCapture(@"{ audio: false, video: false }", false);
+}
+
+TEST_F(GetDisplayMediaTest, Constraints)
+{
+ promptForCapture(@"{ video: {width: 640} }", false);
+ promptForCapture(@"{ video: true, audio: { volume: 0.5 } }", false);
+ promptForCapture(@"{ video: {height: 480}, audio: true }", false);
+}
+
+} // namespace TestWebKitAPI
+
+#endif // ENABLE(MEDIA_STREAM)
+
+#endif // WK_API_ENABLED