Diff
Modified: trunk/Source/WebCore/ChangeLog (284294 => 284295)
--- trunk/Source/WebCore/ChangeLog 2021-10-16 00:00:09 UTC (rev 284294)
+++ trunk/Source/WebCore/ChangeLog 2021-10-16 00:34:25 UTC (rev 284295)
@@ -1,3 +1,106 @@
+2021-10-15 Eric Carlson <[email protected]>
+
+ [iOS] Support getDisplayMedia
+ https://bugs.webkit.org/show_bug.cgi?id=231455
+ <rdar://problem/84044495>
+
+ Reviewed by Youenn Fablet and Jer Noble.
+
+ Implement screen capture for iOS using ReplayKit. ReplayKit only captures when the
+ host application is in the foreground, so the MediaStream track is muted when the
+ app is backgrounded.
+
+ getDisplayMedia availability to _javascript_ is controlled by the `ScreenCaptureEnabled`
+ setting, which is disabled by default on iOS.
+
+ I haven't figured out how to test this automatically yet because ReplayKit always
+ shows its own modal user prompt before it allows capture to begin.
+
+ * SourcesCocoa.txt: Add ReplayKitCaptureSource.mm. Rename DisplayCaptureSourceMac.cpp
+ to DisplayCaptureSourceCocoa.cpp.
+
+ * WebCore.xcodeproj/project.pbxproj: Add new files.
+
+ * en.lproj/Localizable.strings: Add localizable strings for getDisplayMedia prompt.
+
+ * platform/graphics/cv/ImageTransferSessionVT.h:
+ * platform/graphics/cv/ImageTransferSessionVT.mm:
+ (WebCore::ImageTransferSessionVT::convertCMSampleBuffer): Add an optional MediaTime parameter.
+ (WebCore::ImageTransferSessionVT::createMediaSample): Add a MediaTime parameter.
+
+ * platform/mediastream/ios/ReplayKitCaptureSource.h: Added.
+ * platform/mediastream/ios/ReplayKitCaptureSource.mm: Added.
+ (-[WebCoreReplayKitScreenRecorderHelper initWithCallback:]):
+ (-[WebCoreReplayKitScreenRecorderHelper disconnect]):
+ (-[WebCoreReplayKitScreenRecorderHelper observeValueForKeyPath:ofObject:change:context:]):
+ (WebCore::ReplayKitCaptureSource::isAvailable): Check ReplayKit availability.
+ (WebCore::ReplayKitCaptureSource::create):
+ (WebCore::ReplayKitCaptureSource::ReplayKitCaptureSource):
+ (WebCore::ReplayKitCaptureSource::~ReplayKitCaptureSource):
+ (WebCore::ReplayKitCaptureSource::start): Start screen capture only.
+ (WebCore::ReplayKitCaptureSource::screenRecorderDidOutputVideoSample): Retain the
+ the new frame, set intrinsic size to the image size.
+ (WebCore::ReplayKitCaptureSource::captureStateDidChange): Update observer if interruption
+ state or recorder state changes so it can update the track's 'muted' state.
+ (WebCore::ReplayKitCaptureSource::stop): Stop capture.
+ (WebCore::ReplayKitCaptureSource::generateFrame):
+ (WebCore::ReplayKitCaptureSource::verifyCaptureIsActive): ReplayKit doesn't notify
+ when capture is paused, so watch for changes by monitoring the frame count.
+ (WebCore::ReplayKitCaptureSource::startCaptureWatchdogTimer): Start the timer that
+ will monitor for capture pausing/resuming.
+ (WebCore::screenDeviceUUID):
+ (WebCore::screenDevice):
+ (WebCore::ReplayKitCaptureSource::screenCaptureDeviceWithPersistentID):
+ (WebCore::ReplayKitCaptureSource::screenCaptureDevices):
+
+ * platform/mediastream/mac/CGDisplayStreamCaptureSource.cpp:
+ (WebCore::CGDisplayStreamCaptureSource::generateFrame): DisplayCaptureSourceMac was
+ renamed DisplayCaptureSourceCocoa.
+ (WebCore::CGDisplayStreamCaptureSource::newFrame): Take a RetainPtr<IOSurfaceRef>
+ instead of a DisplaySurface.
+ (WebCore::CGDisplayStreamCaptureSource::frameAvailableHandler): Ditto.
+ * platform/mediastream/mac/CGDisplayStreamCaptureSource.h:
+ (WebCore::CGDisplayStreamCaptureSource::DisplaySurface::DisplaySurface): Deleted.
+ (WebCore::CGDisplayStreamCaptureSource::DisplaySurface::~DisplaySurface): Deleted.
+ (WebCore::CGDisplayStreamCaptureSource::DisplaySurface::operator=): Deleted.
+ (WebCore::CGDisplayStreamCaptureSource::DisplaySurface::ioSurface const): Deleted.
+
+ * platform/mediastream/mac/CGDisplayStreamScreenCaptureSource.h:
+ * platform/mediastream/mac/CGDisplayStreamScreenCaptureSource.mm:
+ (WebCore::CGDisplayStreamScreenCaptureSource::create): DisplayCaptureSourceMac was
+ renamed DisplayCaptureSourceCocoa.
+
+ * platform/mediastream/mac/DisplayCaptureManagerCocoa.cpp:
+ (WebCore::DisplayCaptureManagerCocoa::updateDisplayCaptureDevices): Use
+ ReplayKitCaptureSource on iOS.
+
+ * platform/mediastream/mac/DisplayCaptureSourceCocoa.cpp: Renamed from Source/WebCore/platform/mediastream/mac/DisplayCaptureSourceMac.cpp.
+ (WebCore::DisplayCaptureSourceCocoa::create):
+ (WebCore::DisplayCaptureSourceCocoa::DisplayCaptureSourceCocoa):
+ (WebCore::DisplayCaptureSourceCocoa::~DisplayCaptureSourceCocoa):
+ (WebCore::DisplayCaptureSourceCocoa::capabilities):
+ (WebCore::DisplayCaptureSourceCocoa::settings):
+ (WebCore::DisplayCaptureSourceCocoa::settingsDidChange):
+ (WebCore::DisplayCaptureSourceCocoa::startProducingData):
+ (WebCore::DisplayCaptureSourceCocoa::stopProducingData):
+ (WebCore::DisplayCaptureSourceCocoa::elapsedTime):
+ (WebCore::DisplayCaptureSourceCocoa::updateFrameSize):
+ (WebCore::DisplayCaptureSourceCocoa::emitFrame): Support capturer returning a CMSampleBuffer.
+ (WebCore::DisplayCaptureSourceCocoa::setLogger):
+ (WebCore::DisplayCaptureSourceCocoa::Capturer::setLogger): Set the capturer's logger.
+ (WebCore::DisplayCaptureSourceCocoa::Capturer::logChannel const):
+ (WebCore::DisplayCaptureSourceCocoa::Capturer::Observer::~Observer):
+ (WebCore::DisplayCaptureSourceCocoa::Capturer::setObserver):
+ (WebCore::DisplayCaptureSourceCocoa::Capturer::capturerIsRunningChanged):
+ * platform/mediastream/mac/DisplayCaptureSourceCocoa.h: Renamed from Source/WebCore/platform/mediastream/mac/DisplayCaptureSourceMac.h.
+
+ * platform/mediastream/mac/RealtimeMediaSourceCenterMac.cpp:
+ (WebCore::DisplayCaptureSourceFactoryMac::createDisplayCaptureSource): DisplayCaptureSourceMac
+ renamed to DisplayCaptureSourceCocoa.
+
+ * platform/mock/MockRealtimeMediaSourceCenter.cpp:
+ (WebCore::MockDisplayCapturer::generateFrame): Ditto.
+
2021-10-15 Aditya Keerthi <[email protected]>
[iOS] Support accent-color for button-like controls
Modified: trunk/Source/WebCore/PAL/ChangeLog (284294 => 284295)
--- trunk/Source/WebCore/PAL/ChangeLog 2021-10-16 00:00:09 UTC (rev 284294)
+++ trunk/Source/WebCore/PAL/ChangeLog 2021-10-16 00:34:25 UTC (rev 284295)
@@ -1,3 +1,15 @@
+2021-10-15 Eric Carlson <[email protected]>
+
+ [iOS] Support getDisplayMedia
+ https://bugs.webkit.org/show_bug.cgi?id=231455
+ <rdar://problem/84044495>
+
+ Reviewed by Youenn Fablet and Jer Noble.
+
+ * PAL.xcodeproj/project.pbxproj:
+ * pal/ios/ReplayKitSoftLink.h: Added.
+ * pal/ios/ReplayKitSoftLink.mm: Added.
+
2021-10-14 Alex Christensen <[email protected]>
Fix non-internal iOS builds after r284220
Modified: trunk/Source/WebCore/PAL/PAL.xcodeproj/project.pbxproj (284294 => 284295)
--- trunk/Source/WebCore/PAL/PAL.xcodeproj/project.pbxproj 2021-10-16 00:00:09 UTC (rev 284294)
+++ trunk/Source/WebCore/PAL/PAL.xcodeproj/project.pbxproj 2021-10-16 00:34:25 UTC (rev 284295)
@@ -21,6 +21,8 @@
/* End PBXAggregateTarget section */
/* Begin PBXBuildFile section */
+ 071C00372707EDF000D027C7 /* ReplayKitSoftLink.mm in Sources */ = {isa = PBXBuildFile; fileRef = 071C00352707EDF000D027C7 /* ReplayKitSoftLink.mm */; };
+ 071C00382707EDF000D027C7 /* ReplayKitSoftLink.h in Headers */ = {isa = PBXBuildFile; fileRef = 071C00362707EDF000D027C7 /* ReplayKitSoftLink.h */; };
07611DB6243FA5BF00D80704 /* UsageTrackingSoftLink.h in Headers */ = {isa = PBXBuildFile; fileRef = 07611DB4243FA5BE00D80704 /* UsageTrackingSoftLink.h */; };
07611DB7243FA5BF00D80704 /* UsageTrackingSoftLink.mm in Sources */ = {isa = PBXBuildFile; fileRef = 07611DB5243FA5BF00D80704 /* UsageTrackingSoftLink.mm */; };
077E87B1226A460200A2AFF0 /* AVFoundationSoftLink.mm in Sources */ = {isa = PBXBuildFile; fileRef = 077E87AF226A460200A2AFF0 /* AVFoundationSoftLink.mm */; };
@@ -236,6 +238,8 @@
/* End PBXContainerItemProxy section */
/* Begin PBXFileReference section */
+ 071C00352707EDF000D027C7 /* ReplayKitSoftLink.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = ReplayKitSoftLink.mm; sourceTree = "<group>"; };
+ 071C00362707EDF000D027C7 /* ReplayKitSoftLink.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ReplayKitSoftLink.h; sourceTree = "<group>"; };
07611DB4243FA5BE00D80704 /* UsageTrackingSoftLink.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = UsageTrackingSoftLink.h; sourceTree = "<group>"; };
07611DB5243FA5BF00D80704 /* UsageTrackingSoftLink.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = UsageTrackingSoftLink.mm; sourceTree = "<group>"; };
077E87AF226A460200A2AFF0 /* AVFoundationSoftLink.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = AVFoundationSoftLink.mm; sourceTree = "<group>"; };
@@ -774,6 +778,8 @@
5C7C787223AC3E770065F47E /* ManagedConfigurationSoftLink.mm */,
4450FC9E21F5F602004DFA56 /* QuickLookSoftLink.h */,
4450FC9D21F5F602004DFA56 /* QuickLookSoftLink.mm */,
+ 071C00362707EDF000D027C7 /* ReplayKitSoftLink.h */,
+ 071C00352707EDF000D027C7 /* ReplayKitSoftLink.mm */,
079D1D9526950DD700883577 /* SystemStatusSoftLink.h */,
079D1D9626950DD700883577 /* SystemStatusSoftLink.mm */,
2E1342CA215AA10A007199D2 /* UIKitSoftLink.h */,
@@ -995,6 +1001,7 @@
4450FCA021F5F602004DFA56 /* QuickLookSoftLink.h in Headers */,
0C5AF9201F43A4C7002EAC02 /* QuickLookSPI.h in Headers */,
F4C85A4F2658551A005B89CC /* QuickLookUISoftLink.h in Headers */,
+ 071C00382707EDF000D027C7 /* ReplayKitSoftLink.h in Headers */,
F4974EA3265EEA2200B49B8C /* RevealSoftLink.h in Headers */,
442956CD218A72DF0080DB54 /* RevealSPI.h in Headers */,
570AB8F120AE2E8D00B8BE87 /* SecKeyProxySPI.h in Headers */,
@@ -1140,6 +1147,7 @@
A1175B4F1F6B337300C4B9F0 /* PopupMenu.mm in Sources */,
4450FC9F21F5F602004DFA56 /* QuickLookSoftLink.mm in Sources */,
F4C85A4E2658551A005B89CC /* QuickLookUISoftLink.mm in Sources */,
+ 071C00372707EDF000D027C7 /* ReplayKitSoftLink.mm in Sources */,
F4974EA4265EEA2200B49B8C /* RevealSoftLink.mm in Sources */,
A3C66CDC1F462D6A009E6EE9 /* SessionID.cpp in Sources */,
A3AB6E521F3D1DC5009C14B1 /* SleepDisabler.cpp in Sources */,
Added: trunk/Source/WebCore/PAL/pal/ios/ReplayKitSoftLink.h (0 => 284295)
--- trunk/Source/WebCore/PAL/pal/ios/ReplayKitSoftLink.h (rev 0)
+++ trunk/Source/WebCore/PAL/pal/ios/ReplayKitSoftLink.h 2021-10-16 00:34:25 UTC (rev 284295)
@@ -0,0 +1,36 @@
+/*
+ * Copyright (C) 2021 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.
+ */
+
+#pragma once
+
+#if PLATFORM(IOS)
+
+#import <ReplayKit/ReplayKit.h>
+#import <wtf/SoftLinking.h>
+
+SOFT_LINK_FRAMEWORK_FOR_HEADER(PAL, ReplayKit)
+
+SOFT_LINK_CLASS_FOR_HEADER(PAL, RPScreenRecorder)
+
+#endif
Added: trunk/Source/WebCore/PAL/pal/ios/ReplayKitSoftLink.mm (0 => 284295)
--- trunk/Source/WebCore/PAL/pal/ios/ReplayKitSoftLink.mm (rev 0)
+++ trunk/Source/WebCore/PAL/pal/ios/ReplayKitSoftLink.mm 2021-10-16 00:34:25 UTC (rev 284295)
@@ -0,0 +1,36 @@
+/*
+ * Copyright (C) 2021 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 PLATFORM(IOS)
+
+#import <ReplayKit/ReplayKit.h>
+#import <wtf/SoftLinking.h>
+
+SOFT_LINK_FRAMEWORK_FOR_SOURCE(PAL, ReplayKit)
+
+SOFT_LINK_CLASS_FOR_SOURCE_WITH_EXPORT(PAL, ReplayKit, RPScreenRecorder, PAL_EXPORT)
+
+#endif
Modified: trunk/Source/WebCore/PAL/pal/spi/cf/CoreAudioSPI.h (284294 => 284295)
--- trunk/Source/WebCore/PAL/pal/spi/cf/CoreAudioSPI.h 2021-10-16 00:00:09 UTC (rev 284294)
+++ trunk/Source/WebCore/PAL/pal/spi/cf/CoreAudioSPI.h 2021-10-16 00:34:25 UTC (rev 284295)
@@ -27,6 +27,8 @@
#if PLATFORM(COCOA)
+#include <CoreAudio/CoreAudioTypes.h>
+
#if USE(APPLE_INTERNAL_SDK)
#include <CoreAudio/AudioHardwarePriv.h>
#else
Modified: trunk/Source/WebCore/SourcesCocoa.txt (284294 => 284295)
--- trunk/Source/WebCore/SourcesCocoa.txt 2021-10-16 00:00:09 UTC (rev 284294)
+++ trunk/Source/WebCore/SourcesCocoa.txt 2021-10-16 00:34:25 UTC (rev 284295)
@@ -522,9 +522,11 @@
platform/mediastream/cocoa/AudioMediaStreamTrackRendererCocoa.cpp
platform/mediastream/cocoa/AudioMediaStreamTrackRendererInternalUnit.cpp
platform/mediastream/cocoa/AudioMediaStreamTrackRendererUnit.cpp
+platform/mediastream/cocoa/DisplayCaptureSourceCocoa.cpp
platform/mediastream/ios/AVAudioSessionCaptureDevice.mm
platform/mediastream/ios/AVAudioSessionCaptureDeviceManager.mm @no-unify
platform/mediastream/ios/CoreAudioCaptureSourceIOS.mm
+platform/mediastream/ios/ReplayKitCaptureSource.mm @no-unify
platform/mediastream/libwebrtc/LibWebRTCProviderCocoa.cpp
platform/mediastream/mac/AVCaptureDeviceManager.mm
platform/mediastream/mac/AVVideoCaptureSource.mm @no-unify
@@ -535,7 +537,6 @@
platform/mediastream/mac/CoreAudioCaptureDeviceManager.cpp
platform/mediastream/mac/CoreAudioCaptureSource.cpp
platform/mediastream/mac/DisplayCaptureManagerCocoa.cpp
-platform/mediastream/mac/DisplayCaptureSourceMac.cpp
platform/mediastream/mac/MediaStreamTrackAudioSourceProviderCocoa.cpp
platform/mediastream/mac/MockAudioSharedUnit.mm
platform/mediastream/mac/MockRealtimeVideoSourceMac.mm
Modified: trunk/Source/WebCore/WebCore.xcodeproj/project.pbxproj (284294 => 284295)
--- trunk/Source/WebCore/WebCore.xcodeproj/project.pbxproj 2021-10-16 00:00:09 UTC (rev 284294)
+++ trunk/Source/WebCore/WebCore.xcodeproj/project.pbxproj 2021-10-16 00:34:25 UTC (rev 284295)
@@ -98,6 +98,8 @@
070E81D11BF27656001FDA48 /* VideoTrackPrivateMediaStream.h in Headers */ = {isa = PBXBuildFile; fileRef = 070E81D01BF27656001FDA48 /* VideoTrackPrivateMediaStream.h */; };
070F549817F12F6B00169E04 /* MediaStreamConstraintsValidationClient.h in Headers */ = {isa = PBXBuildFile; fileRef = 070F549717F12F6B00169E04 /* MediaStreamConstraintsValidationClient.h */; };
071A9EC3168FBC55002629F9 /* TextTrackCueGeneric.h in Headers */ = {isa = PBXBuildFile; fileRef = 071A9EC1168FB56C002629F9 /* TextTrackCueGeneric.h */; settings = {ATTRIBUTES = (Private, ); }; };
+ 071C00342707D95500D027C7 /* ReplayKitCaptureSource.h in Headers */ = {isa = PBXBuildFile; fileRef = 071C00332707D94400D027C7 /* ReplayKitCaptureSource.h */; };
+ 071C004B270B864900D027C7 /* ReplayKitCaptureSource.mm in Sources */ = {isa = PBXBuildFile; fileRef = 071C00322707D94300D027C7 /* ReplayKitCaptureSource.mm */; };
071E49701AD5AB5E008A50B4 /* MediaPlaybackTargetCocoa.h in Headers */ = {isa = PBXBuildFile; fileRef = 071E496F1AD5AB5E008A50B4 /* MediaPlaybackTargetCocoa.h */; settings = {ATTRIBUTES = (Private, ); }; };
0725EFA9239AD79300A538A9 /* MediaPlayerPrivate.h in Headers */ = {isa = PBXBuildFile; fileRef = 079F5E4B0F3BEBEA005E0782 /* MediaPlayerPrivate.h */; settings = {ATTRIBUTES = (Private, ); }; };
07277E4D17D018CC0015534D /* JSMediaStream.h in Headers */ = {isa = PBXBuildFile; fileRef = 07277E4117D018CC0015534D /* JSMediaStream.h */; };
@@ -207,6 +209,7 @@
07B7116D1D899E63009F0FFB /* CaptureDevice.h in Headers */ = {isa = PBXBuildFile; fileRef = 07B7116A1D899E63009F0FFB /* CaptureDevice.h */; settings = {ATTRIBUTES = (Private, ); }; };
07B7116F1D899E63009F0FFB /* CaptureDeviceManager.h in Headers */ = {isa = PBXBuildFile; fileRef = 07B7116C1D899E63009F0FFB /* CaptureDeviceManager.h */; settings = {ATTRIBUTES = (Private, ); }; };
07B93FFC23B94EC70036F8EA /* MIMETypeCache.h in Headers */ = {isa = PBXBuildFile; fileRef = 07B93FF923B92AAA0036F8EA /* MIMETypeCache.h */; settings = {ATTRIBUTES = (Private, ); }; };
+ 07BB1E7027176CD9001DF289 /* DisplayCaptureSourceCocoa.h in Headers */ = {isa = PBXBuildFile; fileRef = 07BB1E6F27176CCA001DF289 /* DisplayCaptureSourceCocoa.h */; };
07C046C41E42508B007201E7 /* CAAudioStreamDescription.h in Headers */ = {isa = PBXBuildFile; fileRef = 073B87581E40DCFD0071C0EC /* CAAudioStreamDescription.h */; settings = {ATTRIBUTES = (Private, ); }; };
07C046CB1E426413007201E7 /* AudioStreamDescription.h in Headers */ = {isa = PBXBuildFile; fileRef = 073B87561E40DCE50071C0EC /* AudioStreamDescription.h */; settings = {ATTRIBUTES = (Private, ); }; };
07C1482E2612A21F00775828 /* MediaSessionCoordinatorState.h in Headers */ = {isa = PBXBuildFile; fileRef = 077BA58826126D660072F19F /* MediaSessionCoordinatorState.h */; settings = {ATTRIBUTES = (Private, ); }; };
@@ -5882,6 +5885,8 @@
0717765F26C303B700A63299 /* CGDisplayStreamScreenCaptureSource.mm */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.objcpp; path = CGDisplayStreamScreenCaptureSource.mm; sourceTree = "<group>"; };
071A9EC0168FB56C002629F9 /* TextTrackCueGeneric.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = TextTrackCueGeneric.cpp; sourceTree = "<group>"; };
071A9EC1168FB56C002629F9 /* TextTrackCueGeneric.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = TextTrackCueGeneric.h; sourceTree = "<group>"; };
+ 071C00322707D94300D027C7 /* ReplayKitCaptureSource.mm */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.objcpp; path = ReplayKitCaptureSource.mm; sourceTree = "<group>"; };
+ 071C00332707D94400D027C7 /* ReplayKitCaptureSource.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = ReplayKitCaptureSource.h; sourceTree = "<group>"; };
071E496D1AD5AA0D008A50B4 /* MediaPlaybackTargetCocoa.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = MediaPlaybackTargetCocoa.mm; sourceTree = "<group>"; };
071E496F1AD5AB5E008A50B4 /* MediaPlaybackTargetCocoa.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MediaPlaybackTargetCocoa.h; sourceTree = "<group>"; };
07221B4C17CEC32700848E51 /* MediaStream.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = MediaStream.cpp; sourceTree = "<group>"; };
@@ -6070,10 +6075,8 @@
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 /* DisplayCaptureSourceMac.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = DisplayCaptureSourceMac.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 /* DisplayCaptureSourceMac.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = DisplayCaptureSourceMac.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>"; };
@@ -6093,6 +6096,8 @@
07B7116C1D899E63009F0FFB /* CaptureDeviceManager.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = CaptureDeviceManager.h; sourceTree = "<group>"; };
07B93FF923B92AAA0036F8EA /* MIMETypeCache.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = MIMETypeCache.h; sourceTree = "<group>"; };
07B93FFB23B92AAB0036F8EA /* MIMETypeCache.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = MIMETypeCache.cpp; sourceTree = "<group>"; };
+ 07BB1E6E27176CCA001DF289 /* DisplayCaptureSourceCocoa.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = DisplayCaptureSourceCocoa.cpp; sourceTree = "<group>"; };
+ 07BB1E6F27176CCA001DF289 /* DisplayCaptureSourceCocoa.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = DisplayCaptureSourceCocoa.h; sourceTree = "<group>"; };
07C148292612955C00775828 /* JSMediaSessionReadyState.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = JSMediaSessionReadyState.h; sourceTree = "<group>"; };
07C1482B2612955D00775828 /* JSMediaSessionReadyState.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = JSMediaSessionReadyState.cpp; sourceTree = "<group>"; };
07C1482C2612955E00775828 /* JSMediaSessionCoordinatorState.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = JSMediaSessionCoordinatorState.cpp; sourceTree = "<group>"; };
@@ -17837,8 +17842,6 @@
3F3BB5831E709EE400C701F2 /* CoreAudioCaptureSource.h */,
07A6D8481FEB700B006441DE /* DisplayCaptureManagerCocoa.cpp */,
07A6D8491FEB700C006441DE /* DisplayCaptureManagerCocoa.h */,
- 07A6D8471FEB700B006441DE /* DisplayCaptureSourceMac.cpp */,
- 07A6D84A1FEB700D006441DE /* DisplayCaptureSourceMac.h */,
4174E9202535DCDD00FE4202 /* MediaStreamTrackAudioSourceProviderCocoa.cpp */,
4174E91E2535DCD600FE4202 /* MediaStreamTrackAudioSourceProviderCocoa.h */,
0744ECEB1E0C4AE5000D0944 /* MockAudioSharedUnit.h */,
@@ -20154,6 +20157,8 @@
41C3B89F2649B1B7004ED4DE /* AudioMediaStreamTrackRendererInternalUnit.h */,
41C3B8A02649B1B7004ED4DE /* AudioMediaStreamTrackRendererUnit.cpp */,
41C3B89B2649B1B6004ED4DE /* AudioMediaStreamTrackRendererUnit.h */,
+ 07BB1E6E27176CCA001DF289 /* DisplayCaptureSourceCocoa.cpp */,
+ 07BB1E6F27176CCA001DF289 /* DisplayCaptureSourceCocoa.h */,
);
path = cocoa;
sourceTree = "<group>";
@@ -28851,6 +28856,8 @@
CDC675201EAEA9B700727C84 /* AVAudioSessionCaptureDeviceManager.mm */,
07AFF4201EFB144700B545B3 /* CoreAudioCaptureSourceIOS.h */,
07AFF4211EFB144700B545B3 /* CoreAudioCaptureSourceIOS.mm */,
+ 071C00332707D94400D027C7 /* ReplayKitCaptureSource.h */,
+ 071C00322707D94300D027C7 /* ReplayKitCaptureSource.mm */,
);
path = ios;
sourceTree = "<group>";
@@ -32516,6 +32523,7 @@
835D54C51F4DE53800E60671 /* DirectoryFileListCreator.h in Headers */,
F47A09D120A93A9700240FAE /* DisabledAdaptations.h in Headers */,
7EDAAFC919A2CCDC0034DFD1 /* DiskCacheMonitorCocoa.h in Headers */,
+ 07BB1E7027176CD9001DF289 /* DisplayCaptureSourceCocoa.h in Headers */,
0FE5FBD31C3DD51E0007A2CA /* DisplayList.h in Headers */,
55AD09402408964000DE4D2F /* DisplayListDrawingContext.h in Headers */,
55AD093E2408963500DE4D2F /* DisplayListImageBuffer.h in Headers */,
@@ -35149,6 +35157,7 @@
A89CCC530F44E98100B5DA10 /* ReplaceNodeWithSpanCommand.h in Headers */,
2DF512CE1D873E47001D6780 /* ReplaceRangeWithTextCommand.h in Headers */,
93309E0A099E64920056E581 /* ReplaceSelectionCommand.h in Headers */,
+ 071C00342707D95500D027C7 /* ReplayKitCaptureSource.h in Headers */,
46DD6E1F26E7DBE7008C1F4C /* ReportingEndpointsCache.h in Headers */,
4998AEC613F9D0EA0090B1AA /* RequestAnimationFrameCallback.h in Headers */,
F55B3DD01251F12D003EF269 /* ResetInputType.h in Headers */,
@@ -36913,6 +36922,7 @@
CDA29A301CBF74D400901CCF /* PlaybackSessionInterfaceAVKit.mm in Sources */,
CDA29A161CBDA56C00901CCF /* PlaybackSessionInterfaceMac.mm in Sources */,
419242492127B93E00634FCF /* RealtimeOutgoingVideoSourceCocoa.mm in Sources */,
+ 071C004B270B864900D027C7 /* ReplayKitCaptureSource.mm in Sources */,
5C2B1AEC22397EBC00B91CF7 /* ResourceResponseCocoa.mm in Sources */,
BC51156E12B1749C00C96754 /* ScrollAnimatorMac.mm in Sources */,
0FEE371126F19529001B5184 /* ScrollbarsControllerMac.mm in Sources */,
Modified: trunk/Source/WebCore/en.lproj/Localizable.strings (284294 => 284295)
--- trunk/Source/WebCore/en.lproj/Localizable.strings 2021-10-16 00:00:09 UTC (rev 284294)
+++ trunk/Source/WebCore/en.lproj/Localizable.strings 2021-10-16 00:34:25 UTC (rev 284295)
@@ -163,6 +163,9 @@
/* Allow button title in user media prompt */
"Allow (usermedia)" = "Allow";
+/* Allow button title in screen sharing prompt */
+"Allow (screensharing)" = "Allow";
+
/* Message for requesting cross-site cookie and website data access. */
"Allow “%@” and “%@” to use cookies and website data while browsing “%@”?" = "Allow “%@” and “%@” to use cookies and website data while browsing “%@”?";
@@ -184,6 +187,9 @@
/* Message for user microphone access prompt */
"Allow “%@” to use your microphone?" = "Allow “%@” to use your microphone?";
+/* Message for screen sharing prompt. */
+"Allow “%@” to observe your screen?" = "Allow “%@” to observe your screen?";
+
/* WKErrorUnknown description */
"An unknown error occurred" = "An unknown error occurred";
@@ -391,6 +397,9 @@
/* Disallow button title in user media prompt */
"Don’t Allow (usermedia)" = "Don’t Allow";
+/* Disallow button title in screen sharing prompt */
+"Don’t Allow (screensharing)" = "Don’t Allow";
+
/* Download Audio To Disk context menu item */
"Download Audio" = "Download Audio";
Modified: trunk/Source/WebCore/platform/graphics/cv/ImageTransferSessionVT.h (284294 => 284295)
--- trunk/Source/WebCore/platform/graphics/cv/ImageTransferSessionVT.h 2021-10-16 00:00:09 UTC (rev 284294)
+++ trunk/Source/WebCore/platform/graphics/cv/ImageTransferSessionVT.h 2021-10-16 00:34:25 UTC (rev 284295)
@@ -49,7 +49,7 @@
RefPtr<MediaSample> convertMediaSample(MediaSample&, const IntSize&);
RefPtr<MediaSample> createMediaSample(CGImageRef, const MediaTime&, const IntSize&, MediaSample::VideoRotation = MediaSample::VideoRotation::None, bool mirrored = false);
- RefPtr<MediaSample> createMediaSample(CMSampleBufferRef, const IntSize&, MediaSample::VideoRotation = MediaSample::VideoRotation::None, bool mirrored = false);
+ RefPtr<MediaSample> createMediaSample(CMSampleBufferRef, const MediaTime&, const IntSize&, MediaSample::VideoRotation = MediaSample::VideoRotation::None, bool mirrored = false);
#if !PLATFORM(MACCATALYST)
WEBCORE_EXPORT RefPtr<MediaSample> createMediaSample(IOSurfaceRef, const MediaTime&, const IntSize&, MediaSample::VideoRotation = MediaSample::VideoRotation::None, bool mirrored = false);
@@ -67,7 +67,7 @@
RetainPtr<CMSampleBufferRef> createCMSampleBuffer(IOSurfaceRef, const MediaTime&, const IntSize&);
#endif
- RetainPtr<CMSampleBufferRef> convertCMSampleBuffer(CMSampleBufferRef, const IntSize&);
+ RetainPtr<CMSampleBufferRef> convertCMSampleBuffer(CMSampleBufferRef, const IntSize&, const MediaTime* = nullptr);
RetainPtr<CMSampleBufferRef> createCMSampleBuffer(CVPixelBufferRef, const MediaTime&, const IntSize&);
RetainPtr<CMSampleBufferRef> createCMSampleBuffer(CGImageRef, const MediaTime&, const IntSize&);
Modified: trunk/Source/WebCore/platform/graphics/cv/ImageTransferSessionVT.mm (284294 => 284295)
--- trunk/Source/WebCore/platform/graphics/cv/ImageTransferSessionVT.mm 2021-10-16 00:00:09 UTC (rev 284294)
+++ trunk/Source/WebCore/platform/graphics/cv/ImageTransferSessionVT.mm 2021-10-16 00:34:25 UTC (rev 284295)
@@ -108,7 +108,7 @@
return outputBuffer;
}
-RetainPtr<CMSampleBufferRef> ImageTransferSessionVT::convertCMSampleBuffer(CMSampleBufferRef sourceBuffer, const IntSize& size)
+RetainPtr<CMSampleBufferRef> ImageTransferSessionVT::convertCMSampleBuffer(CMSampleBufferRef sourceBuffer, const IntSize& size, const MediaTime* sampleTime)
{
if (!sourceBuffer)
return nullptr;
@@ -141,6 +141,14 @@
RELEASE_LOG(Media, "ImageTransferSessionVT::convertCMSampleBuffer: CMSampleBufferGetSampleTimingInfoArray failed with error code: %d", static_cast<int>(status));
return nullptr;
}
+
+ if (sampleTime) {
+ auto cmTime = PAL::toCMTime(*sampleTime);
+ for (auto& timing : timingInfoArray) {
+ timing.presentationTimeStamp = cmTime;
+ timing.decodeTimeStamp = cmTime;
+ }
+ }
timeingInfoPtr = timingInfoArray.data();
}
@@ -287,9 +295,9 @@
return MediaSampleAVFObjC::create(sampleBuffer.get(), rotation, mirrored);
}
-RefPtr<MediaSample> ImageTransferSessionVT::createMediaSample(CMSampleBufferRef buffer, const IntSize& size, MediaSample::VideoRotation rotation, bool mirrored)
+RefPtr<MediaSample> ImageTransferSessionVT::createMediaSample(CMSampleBufferRef buffer, const MediaTime& sampleTime, const IntSize& size, MediaSample::VideoRotation rotation, bool mirrored)
{
- auto sampleBuffer = convertCMSampleBuffer(buffer, size);
+ auto sampleBuffer = convertCMSampleBuffer(buffer, size, &sampleTime);
if (!sampleBuffer)
return nullptr;
Copied: trunk/Source/WebCore/platform/mediastream/cocoa/DisplayCaptureSourceCocoa.cpp (from rev 284294, trunk/Source/WebCore/platform/mediastream/mac/DisplayCaptureSourceMac.cpp) (0 => 284295)
--- trunk/Source/WebCore/platform/mediastream/cocoa/DisplayCaptureSourceCocoa.cpp (rev 0)
+++ trunk/Source/WebCore/platform/mediastream/cocoa/DisplayCaptureSourceCocoa.cpp 2021-10-16 00:34:25 UTC (rev 284295)
@@ -0,0 +1,311 @@
+/*
+ * Copyright (C) 2017-2021 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) && PLATFORM(COCOA)
+
+#include "CGDisplayStreamScreenCaptureSource.h"
+#include "ImageTransferSessionVT.h"
+#include "Logging.h"
+#include "MediaSampleAVFObjC.h"
+#include "PixelBufferConformerCV.h"
+#include "RealtimeMediaSource.h"
+#include "RealtimeMediaSourceCenter.h"
+#include "RealtimeMediaSourceSettings.h"
+#include "RealtimeVideoUtilities.h"
+#include "RemoteVideoSample.h"
+#include "ReplayKitCaptureSource.h"
+#include "Timer.h"
+#include <CoreMedia/CMSync.h>
+#include <IOSurface/IOSurfaceRef.h>
+#include <mach/mach_time.h>
+#include <pal/avfoundation/MediaTimeAVFoundation.h>
+#include <pal/spi/cf/CoreAudioSPI.h>
+#include <pal/spi/cg/CoreGraphicsSPI.h>
+#include <pal/spi/cocoa/IOSurfaceSPI.h>
+#include <sys/time.h>
+#include <wtf/MainThread.h>
+#include <wtf/NeverDestroyed.h>
+
+#include "CoreVideoSoftLink.h"
+#include <pal/cf/CoreMediaSoftLink.h>
+
+namespace WebCore {
+
+CaptureSourceOrError DisplayCaptureSourceCocoa::create(const CaptureDevice& device, const MediaConstraints* constraints)
+{
+ switch (device.type()) {
+ case CaptureDevice::DeviceType::Screen:
+#if PLATFORM(IOS)
+ return create(ReplayKitCaptureSource::create(device.persistentId()), device, constraints);
+#else
+ return create(CGDisplayStreamScreenCaptureSource::create(device.persistentId()), device, constraints);
+#endif
+ case CaptureDevice::DeviceType::Window:
+ case CaptureDevice::DeviceType::Microphone:
+ case CaptureDevice::DeviceType::Speaker:
+ case CaptureDevice::DeviceType::Camera:
+ case CaptureDevice::DeviceType::Unknown:
+ ASSERT_NOT_REACHED();
+ break;
+ }
+
+ return { };
+}
+
+CaptureSourceOrError DisplayCaptureSourceCocoa::create(Expected<UniqueRef<Capturer>, String>&& capturer, const CaptureDevice& device, const MediaConstraints* constraints)
+{
+ if (!capturer.has_value())
+ return CaptureSourceOrError { WTFMove(capturer.error()) };
+
+ auto source = adoptRef(*new DisplayCaptureSourceCocoa(WTFMove(capturer.value()), String { device.label() }));
+ if (constraints) {
+ auto result = source->applyConstraints(*constraints);
+ if (result)
+ return WTFMove(result.value().badConstraint);
+ }
+
+ return CaptureSourceOrError(WTFMove(source));
+}
+
+DisplayCaptureSourceCocoa::DisplayCaptureSourceCocoa(UniqueRef<Capturer>&& capturer, String&& name)
+ : RealtimeMediaSource(Type::Video, WTFMove(name))
+ , m_capturer(WTFMove(capturer))
+ , m_timer(RunLoop::current(), this, &DisplayCaptureSourceCocoa::emitFrame)
+ , m_capturerIsRunningObserver([weakThis = WeakPtr { *this }] (bool isRunning) { if (weakThis) weakThis->notifyMutedChange(!isRunning); })
+{
+ m_capturer->setIsRunningObserver(&m_capturerIsRunningObserver);
+}
+
+DisplayCaptureSourceCocoa::~DisplayCaptureSourceCocoa()
+{
+}
+
+const RealtimeMediaSourceCapabilities& DisplayCaptureSourceCocoa::capabilities()
+{
+ if (!m_capabilities) {
+ RealtimeMediaSourceCapabilities capabilities(settings().supportedConstraints());
+
+ auto intrinsicSize = m_capturer->intrinsicSize();
+ capabilities.setWidth(CapabilityValueOrRange(1, intrinsicSize.width()));
+ capabilities.setHeight(CapabilityValueOrRange(1, intrinsicSize.height()));
+ capabilities.setFrameRate(CapabilityValueOrRange(.01, 30.0));
+
+ m_capabilities = WTFMove(capabilities);
+ }
+ return m_capabilities.value();
+}
+
+const RealtimeMediaSourceSettings& DisplayCaptureSourceCocoa::settings()
+{
+ if (!m_currentSettings) {
+ RealtimeMediaSourceSettings settings;
+ settings.setFrameRate(frameRate());
+
+ auto size = this->size();
+ settings.setWidth(size.width());
+ settings.setHeight(size.height());
+
+ settings.setDisplaySurface(m_capturer->surfaceType());
+ settings.setLogicalSurface(false);
+
+ RealtimeMediaSourceSupportedConstraints supportedConstraints;
+ supportedConstraints.setSupportsFrameRate(true);
+ supportedConstraints.setSupportsWidth(true);
+ supportedConstraints.setSupportsHeight(true);
+ supportedConstraints.setSupportsDisplaySurface(true);
+ supportedConstraints.setSupportsLogicalSurface(true);
+
+ settings.setSupportedConstraints(supportedConstraints);
+
+ m_currentSettings = WTFMove(settings);
+ }
+ return m_currentSettings.value();
+}
+
+void DisplayCaptureSourceCocoa::settingsDidChange(OptionSet<RealtimeMediaSourceSettings::Flag> settings)
+{
+ if (settings.contains(RealtimeMediaSourceSettings::Flag::FrameRate) && m_timer.isActive())
+ m_timer.startRepeating(1_s / frameRate());
+
+ m_currentSettings = { };
+}
+
+void DisplayCaptureSourceCocoa::startProducingData()
+{
+ m_startTime = MonotonicTime::now();
+ m_timer.startRepeating(1_s / frameRate());
+
+ commitConfiguration();
+ if (!m_capturer->start())
+ captureFailed();
+}
+
+void DisplayCaptureSourceCocoa::stopProducingData()
+{
+ m_timer.stop();
+ m_elapsedTime += MonotonicTime::now() - m_startTime;
+ m_startTime = MonotonicTime::nan();
+
+ m_capturer->stop();
+}
+
+Seconds DisplayCaptureSourceCocoa::elapsedTime()
+{
+ if (std::isnan(m_startTime))
+ return m_elapsedTime;
+
+ return m_elapsedTime + (MonotonicTime::now() - m_startTime);
+}
+
+// We keep the aspect ratio of the intrinsic size for the frame size as getDisplayMedia allows max constraints only.
+void DisplayCaptureSourceCocoa::updateFrameSize()
+{
+ auto intrinsicSize = this->intrinsicSize();
+
+ auto frameSize = size();
+ if (!frameSize.height())
+ frameSize.setHeight(intrinsicSize.height());
+ if (!frameSize.width())
+ frameSize.setWidth(intrinsicSize.width());
+
+ auto maxHeight = std::min(frameSize.height(), intrinsicSize.height());
+ auto maxWidth = std::min(frameSize.width(), intrinsicSize.width());
+
+ auto heightForMaxWidth = maxWidth * intrinsicSize.height() / intrinsicSize.width();
+ auto widthForMaxHeight = maxHeight * intrinsicSize.width() / intrinsicSize.height();
+
+ if (heightForMaxWidth <= maxHeight) {
+ setSize({ maxWidth, heightForMaxWidth });
+ return;
+ }
+ if (widthForMaxHeight <= maxWidth) {
+ setSize({ widthForMaxHeight, maxHeight });
+ return;
+ }
+ setSize(intrinsicSize);
+}
+
+void DisplayCaptureSourceCocoa::emitFrame()
+{
+ if (muted())
+ return;
+
+ if (!m_imageTransferSession)
+ m_imageTransferSession = ImageTransferSessionVT::create(preferedPixelBufferFormat());
+
+ auto sampleTime = MediaTime::createWithDouble((elapsedTime() + 100_ms).seconds());
+
+ auto frame = m_capturer->generateFrame();
+ auto imageSize = WTF::switchOn(frame,
+ [](RetainPtr<IOSurfaceRef>& surface) -> IntSize {
+ if (!surface)
+ return { };
+
+ return IntSize(IOSurfaceGetWidth(surface.get()), IOSurfaceGetHeight(surface.get()));
+ },
+ [](RefPtr<NativeImage>& image) -> IntSize {
+ if (!image)
+ return { };
+
+ return image->size();
+ },
+ [](RetainPtr<CMSampleBufferRef>& sample) -> IntSize {
+ if (!sample)
+ return { };
+
+ CMFormatDescriptionRef formatDescription = PAL::CMSampleBufferGetFormatDescription(sample.get());
+ if (PAL::CMFormatDescriptionGetMediaType(formatDescription) != kCMMediaType_Video)
+ return IntSize();
+
+ return IntSize(PAL::CMVideoFormatDescriptionGetPresentationDimensions(formatDescription, true, true));
+ }
+ );
+
+ if (imageSize.isEmpty())
+ return;
+
+ if (intrinsicSize() != imageSize) {
+ setIntrinsicSize(imageSize);
+ updateFrameSize();
+ }
+
+ auto sample = WTF::switchOn(frame,
+ [this, sampleTime](RetainPtr<IOSurfaceRef>& surface) -> RefPtr<MediaSample> {
+ if (!surface)
+ return nullptr;
+
+ return m_imageTransferSession->createMediaSample(surface.get(), sampleTime, size());
+ },
+ [this, sampleTime](RefPtr<NativeImage>& image) -> RefPtr<MediaSample> {
+ if (!image)
+ return nullptr;
+
+ return m_imageTransferSession->createMediaSample(image->platformImage().get(), sampleTime, size());
+ },
+ [this, sampleTime](RetainPtr<CMSampleBufferRef>& sample) -> RefPtr<MediaSample> {
+ if (!sample)
+ return nullptr;
+
+ return m_imageTransferSession->createMediaSample(sample.get(), sampleTime, size());
+ }
+ );
+
+ if (!sample) {
+ ASSERT_NOT_REACHED();
+ return;
+ }
+
+ videoSampleAvailable(*sample.get());
+}
+
+void DisplayCaptureSourceCocoa::setLogger(const Logger& logger, const void* identifier)
+{
+ RealtimeMediaSource::setLogger(logger, identifier);
+ m_capturer->setLogger(logger, identifier);
+}
+
+void DisplayCaptureSourceCocoa::Capturer::setLogger(const Logger& newLogger, const void* newLogIdentifier)
+{
+ m_logger = &newLogger;
+ m_logIdentifier = newLogIdentifier;
+}
+
+WTFLogChannel& DisplayCaptureSourceCocoa::Capturer::logChannel() const
+{
+ return LogWebRTC;
+}
+
+void DisplayCaptureSourceCocoa::Capturer::capturerIsRunningChanged(bool running)
+{
+ if (m_observer)
+ (*m_observer)(running);
+}
+
+} // namespace WebCore
+
+#endif // ENABLE(MEDIA_STREAM) && PLATFORM(COCOA)
Copied: trunk/Source/WebCore/platform/mediastream/cocoa/DisplayCaptureSourceCocoa.h (from rev 284294, trunk/Source/WebCore/platform/mediastream/mac/DisplayCaptureSourceMac.h) (0 => 284295)
--- trunk/Source/WebCore/platform/mediastream/cocoa/DisplayCaptureSourceCocoa.h (rev 0)
+++ trunk/Source/WebCore/platform/mediastream/cocoa/DisplayCaptureSourceCocoa.h 2021-10-16 00:34:25 UTC (rev 284295)
@@ -0,0 +1,130 @@
+/*
+ * Copyright (C) 2017-2021 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) && PLATFORM(COCOA)
+
+#include "CaptureDevice.h"
+#include "RealtimeMediaSource.h"
+#include <wtf/Observer.h>
+#include <wtf/RefCounted.h>
+#include <wtf/RefPtr.h>
+#include <wtf/RunLoop.h>
+#include <wtf/UniqueRef.h>
+#include <wtf/text/WTFString.h>
+
+
+typedef struct CGImage *CGImageRef;
+typedef struct __CVBuffer *CVPixelBufferRef;
+typedef struct __IOSurface *IOSurfaceRef;
+
+namespace WTF {
+class MediaTime;
+}
+
+namespace WebCore {
+
+class CaptureDeviceInfo;
+class ImageTransferSessionVT;
+class PixelBufferConformerCV;
+
+class DisplayCaptureSourceCocoa final : public RealtimeMediaSource, public CanMakeWeakPtr<DisplayCaptureSourceCocoa> {
+public:
+ using DisplayFrameType = std::variant<RefPtr<NativeImage>, RetainPtr<IOSurfaceRef>, RetainPtr<CMSampleBufferRef>>;
+
+ class Capturer : public LoggerHelper {
+ WTF_MAKE_FAST_ALLOCATED;
+ public:
+ virtual ~Capturer() = default;
+
+ virtual bool start() = 0;
+ virtual void stop() = 0;
+ virtual DisplayFrameType generateFrame() = 0;
+ virtual CaptureDevice::DeviceType deviceType() const = 0;
+ virtual RealtimeMediaSourceSettings::DisplaySurfaceType surfaceType() const = 0;
+ virtual void commitConfiguration(const RealtimeMediaSourceSettings&) = 0;
+ virtual IntSize intrinsicSize() const = 0;
+
+ virtual void setLogger(const Logger&, const void*);
+ const Logger* loggerPtr() const { return m_logger.get(); }
+ const Logger& logger() const final { ASSERT(m_logger); return *m_logger.get(); }
+ const void* logIdentifier() const final { return m_logIdentifier; }
+ WTFLogChannel& logChannel() const final;
+
+ using IsRunningObserver = WTF::Observer<void(bool)>;
+ void setIsRunningObserver(IsRunningObserver* observer) { m_observer = observer; };
+
+ protected:
+ Capturer() = default;
+ void capturerIsRunningChanged(bool);
+
+ private:
+ WeakPtr<IsRunningObserver> m_observer;
+ RefPtr<const Logger> m_logger;
+ const void* m_logIdentifier;
+ };
+
+ static CaptureSourceOrError create(const CaptureDevice&, const MediaConstraints*);
+ static CaptureSourceOrError create(Expected<UniqueRef<Capturer>, String>&&, const CaptureDevice&, const MediaConstraints*);
+
+ Seconds elapsedTime();
+ void updateFrameSize();
+
+private:
+ DisplayCaptureSourceCocoa(UniqueRef<Capturer>&&, String&& name);
+ virtual ~DisplayCaptureSourceCocoa();
+
+ void startProducingData() final;
+ void stopProducingData() final;
+ void settingsDidChange(OptionSet<RealtimeMediaSourceSettings::Flag>) final;
+ bool isCaptureSource() const final { return true; }
+ const RealtimeMediaSourceCapabilities& capabilities() final;
+ const RealtimeMediaSourceSettings& settings() final;
+ CaptureDevice::DeviceType deviceType() const { return m_capturer->deviceType(); }
+ void commitConfiguration() final { m_capturer->commitConfiguration(settings()); }
+
+ const char* logClassName() const final { return "DisplayCaptureSourceCocoa"; }
+ void setLogger(const Logger&, const void*) final;
+
+ void emitFrame();
+
+ UniqueRef<Capturer> m_capturer;
+ std::optional<RealtimeMediaSourceCapabilities> m_capabilities;
+ std::optional<RealtimeMediaSourceSettings> m_currentSettings;
+ RealtimeMediaSourceSupportedConstraints m_supportedConstraints;
+
+ MonotonicTime m_startTime { MonotonicTime::nan() };
+ Seconds m_elapsedTime { 0_s };
+
+ RunLoop::Timer<DisplayCaptureSourceCocoa> m_timer;
+
+ std::unique_ptr<ImageTransferSessionVT> m_imageTransferSession;
+ WTF::Observer<void(bool)> m_capturerIsRunningObserver;
+};
+
+} // namespace WebCore
+
+#endif // ENABLE(MEDIA_STREAM) && PLATFORM(COCOA)
Added: trunk/Source/WebCore/platform/mediastream/ios/ReplayKitCaptureSource.h (0 => 284295)
--- trunk/Source/WebCore/platform/mediastream/ios/ReplayKitCaptureSource.h (rev 0)
+++ trunk/Source/WebCore/platform/mediastream/ios/ReplayKitCaptureSource.h 2021-10-16 00:34:25 UTC (rev 284295)
@@ -0,0 +1,85 @@
+/*
+ * Copyright (C) 2021 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) && PLATFORM(IOS)
+
+#include "DisplayCaptureSourceCocoa.h"
+#include "Timer.h"
+#include <wtf/RetainPtr.h>
+
+OBJC_CLASS RPScreenRecorder;
+OBJC_CLASS WebCoreReplayKitScreenRecorderHelper;
+
+namespace WebCore {
+
+class ReplayKitCaptureSource final : public DisplayCaptureSourceCocoa::Capturer, public CanMakeWeakPtr<ReplayKitCaptureSource> {
+public:
+ static Expected<UniqueRef<DisplayCaptureSourceCocoa::Capturer>, String> create(const String&);
+
+ ReplayKitCaptureSource();
+ virtual ~ReplayKitCaptureSource();
+
+ static bool isAvailable();
+
+ static std::optional<CaptureDevice> screenCaptureDeviceWithPersistentID(const String&);
+ static void screenCaptureDevices(Vector<CaptureDevice>&);
+
+ void captureStateDidChange();
+
+private:
+
+ // DisplayCaptureSourceCocoa::Capturer
+ bool start() final;
+ void stop() final;
+ DisplayCaptureSourceCocoa::DisplayFrameType generateFrame() final;
+ CaptureDevice::DeviceType deviceType() const final { return CaptureDevice::DeviceType::Screen; }
+ RealtimeMediaSourceSettings::DisplaySurfaceType surfaceType() const final { return RealtimeMediaSourceSettings::DisplaySurfaceType::Monitor; }
+ virtual void commitConfiguration(const RealtimeMediaSourceSettings&) { }
+ virtual IntSize intrinsicSize() const { return m_intrinsicSize; }
+
+ // LoggerHelper
+ const char* logClassName() const final { return "ReplayKitCaptureSource"; }
+
+ void screenRecorderDidOutputVideoSample(RetainPtr<CMSampleBufferRef>&&);
+ void startCaptureWatchdogTimer();
+ void verifyCaptureIsActive();
+
+ RetainPtr<CMSampleBufferRef> m_currentFrame;
+ RetainPtr<RPScreenRecorder> m_screenRecorder;
+ RetainPtr<WebCoreReplayKitScreenRecorderHelper> m_recorderHelper;
+
+ Timer m_captureWatchdogTimer;
+ uint64_t m_frameCount { 0 };
+ uint64_t m_lastFrameCount { 0 };
+ IntSize m_intrinsicSize;
+ bool m_isRunning { false };
+ bool m_interrupted { false };
+};
+
+} // namespace WebCore
+
+#endif // ENABLE(MEDIA_STREAM) && PLATFORM(IOS)
Added: trunk/Source/WebCore/platform/mediastream/ios/ReplayKitCaptureSource.mm (0 => 284295)
--- trunk/Source/WebCore/platform/mediastream/ios/ReplayKitCaptureSource.mm (rev 0)
+++ trunk/Source/WebCore/platform/mediastream/ios/ReplayKitCaptureSource.mm 2021-10-16 00:34:25 UTC (rev 284295)
@@ -0,0 +1,281 @@
+/*
+ * Copyright (C) 2021 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 "ReplayKitCaptureSource.h"
+
+#if ENABLE(MEDIA_STREAM) && PLATFORM(IOS)
+
+#import "Logging.h"
+#import "RealtimeVideoUtilities.h"
+#import <wtf/BlockPtr.h>
+#import <wtf/NeverDestroyed.h>
+#import <wtf/UUID.h>
+#import <wtf/text/StringToIntegerConversion.h>
+
+#import <pal/cf/CoreMediaSoftLink.h>
+#import <pal/ios/ReplayKitSoftLink.h>
+
+using namespace WebCore;
+@interface WebCoreReplayKitScreenRecorderHelper : NSObject {
+ WeakPtr<ReplayKitCaptureSource> _callback;
+}
+
+- (instancetype)initWithCallback:(WeakPtr<ReplayKitCaptureSource>&&)callback;
+- (void)disconnect;
+- (void)observeValueForKeyPath:keyPath ofObject:(id)object change:(NSDictionary*)change context:(void*)context;
+@end
+
+@implementation WebCoreReplayKitScreenRecorderHelper
+- (instancetype)initWithCallback:(WeakPtr<ReplayKitCaptureSource>&&)callback
+{
+ self = [super init];
+ if (!self)
+ return self;
+
+ _callback = WTFMove(callback);
+ [[PAL::getRPScreenRecorderClass() sharedRecorder] addObserver:self forKeyPath:@"recording" options:NSKeyValueObservingOptionNew context:(void *)nil];
+
+ return self;
+}
+
+- (void)disconnect
+{
+ _callback = nullptr;
+ [[PAL::getRPScreenRecorderClass() sharedRecorder] removeObserver:self forKeyPath:@"recording"];
+}
+
+- (void)observeValueForKeyPath:keyPath ofObject:(id)object change:(NSDictionary*)change context:(void*)context
+{
+ UNUSED_PARAM(object);
+ UNUSED_PARAM(context);
+
+ if (!_callback)
+ return;
+
+ id newValue = [change valueForKey:NSKeyValueChangeNewKey];
+ bool willChange = [[change valueForKey:NSKeyValueChangeNotificationIsPriorKey] boolValue];
+
+#if !RELEASE_LOG_DISABLED
+ if (_callback->loggerPtr()) {
+ auto identifier = Logger::LogSiteIdentifier("ReplayKitCaptureSource", "observeValueForKeyPath", _callback->logIdentifier());
+ RetainPtr<NSString> valueString = adoptNS([[NSString alloc] initWithFormat:@"%@", newValue]);
+ _callback->logger().logAlways(_callback->logChannel(), identifier, willChange ? "will" : "did", " change '", [keyPath UTF8String], "' to ", [valueString.get() UTF8String]);
+ }
+#endif
+
+ if (willChange)
+ return;
+
+ if ([keyPath isEqualToString:@"recording"])
+ _callback->captureStateDidChange();
+}
+@end
+
+namespace WebCore {
+
+bool ReplayKitCaptureSource::isAvailable()
+{
+ return [PAL::getRPScreenRecorderClass() sharedRecorder].isAvailable;
+}
+
+Expected<UniqueRef<DisplayCaptureSourceCocoa::Capturer>, String> ReplayKitCaptureSource::create(const String&)
+{
+ if (!isAvailable())
+ return makeUnexpected("Screen capture unavailable"_s);
+
+ return UniqueRef<DisplayCaptureSourceCocoa::Capturer>(makeUniqueRef<ReplayKitCaptureSource>());
+}
+
+ReplayKitCaptureSource::ReplayKitCaptureSource()
+ : m_captureWatchdogTimer(*this, &ReplayKitCaptureSource::verifyCaptureIsActive)
+{
+}
+
+ReplayKitCaptureSource::~ReplayKitCaptureSource()
+{
+ [m_recorderHelper disconnect];
+ stop();
+ m_currentFrame = nullptr;
+}
+
+bool ReplayKitCaptureSource::start()
+{
+ ASSERT(isAvailable());
+
+ auto identifier = LOGIDENTIFIER;
+ ALWAYS_LOG_IF(loggerPtr(), identifier);
+
+ auto *screenRecorder = [PAL::getRPScreenRecorderClass() sharedRecorder];
+ if (screenRecorder.recording)
+ return true;
+
+ // FIXME: Add support for concurrent audio capture.
+ [screenRecorder setMicrophoneEnabled:NO];
+
+ if (!m_recorderHelper)
+ m_recorderHelper = ([[WebCoreReplayKitScreenRecorderHelper alloc] initWithCallback:this]);
+
+ auto captureHandler = makeBlockPtr([this, weakThis = WeakPtr { *this }, identifier](CMSampleBufferRef _Nonnull sampleBuffer, RPSampleBufferType bufferType, NSError * _Nullable error) {
+
+ if (bufferType != RPSampleBufferTypeVideo)
+ return;
+
+ ERROR_LOG_IF(error && loggerPtr(), identifier, "startCaptureWithHandler failed ", [error localizedDescription].UTF8String);
+
+ ++m_frameCount;
+
+ RunLoop::main().dispatch([weakThis, sampleBuffer = retainPtr(sampleBuffer)]() mutable {
+ if (!weakThis)
+ return;
+
+ weakThis->screenRecorderDidOutputVideoSample(WTFMove(sampleBuffer));
+ });
+ });
+
+ auto completionHandler = makeBlockPtr([this, weakThis = WeakPtr { *this }, identifier](NSError * _Nullable error) {
+ // FIXME: It should be safe to call `videoSampleAvailable` from any thread. Test this and get rid of this main thread hop.
+ RunLoop::main().dispatch([this, weakThis, error = retainPtr(error), identifier]() mutable {
+ if (!weakThis || !error)
+ return;
+
+ ERROR_LOG_IF(loggerPtr(), identifier, "completionHandler failed ", [error localizedDescription].UTF8String);
+ weakThis->stop();
+ });
+ });
+
+ [screenRecorder startCaptureWithHandler:captureHandler.get() completionHandler:completionHandler.get()];
+
+ return true;
+}
+
+void ReplayKitCaptureSource::screenRecorderDidOutputVideoSample(RetainPtr<CMSampleBufferRef>&& sampleBuffer)
+{
+ m_currentFrame = sampleBuffer.get();
+ m_intrinsicSize = IntSize(PAL::CMVideoFormatDescriptionGetPresentationDimensions(PAL::CMSampleBufferGetFormatDescription(m_currentFrame.get()), true, true));
+}
+
+void ReplayKitCaptureSource::captureStateDidChange()
+{
+ RunLoop::main().dispatch([this, weakThis = WeakPtr { *this }, identifier = LOGIDENTIFIER]() mutable {
+ if (!weakThis)
+ return;
+
+ bool isRecording = !![[PAL::getRPScreenRecorderClass() sharedRecorder] isRecording];
+ if (m_isRunning == (isRecording && !m_interrupted))
+ return;
+
+ m_isRunning = isRecording && !m_interrupted;
+ ALWAYS_LOG_IF(loggerPtr(), identifier, m_isRunning);
+ capturerIsRunningChanged(m_isRunning);
+ });
+}
+
+void ReplayKitCaptureSource::stop()
+{
+ auto identifier = LOGIDENTIFIER;
+ ALWAYS_LOG_IF(loggerPtr(), identifier);
+ m_captureWatchdogTimer.stop();
+ m_interrupted = false;
+ m_isRunning = false;
+
+ auto *screenRecorder = [PAL::getRPScreenRecorderClass() sharedRecorder];
+ if (screenRecorder.recording) {
+ [screenRecorder stopCaptureWithHandler:^(NSError * _Nullable error) {
+ ERROR_LOG_IF(error && loggerPtr(), identifier, "startCaptureWithHandler failed ", [error localizedDescription].UTF8String);
+ }];
+ }
+}
+
+DisplayCaptureSourceCocoa::DisplayFrameType ReplayKitCaptureSource::generateFrame()
+{
+ return m_currentFrame;
+}
+
+void ReplayKitCaptureSource::verifyCaptureIsActive()
+{
+ ASSERT(m_isRunning || m_interrupted);
+ auto identifier = LOGIDENTIFIER;
+ if (m_lastFrameCount != m_frameCount) {
+ m_lastFrameCount = m_frameCount;
+ if (m_interrupted) {
+ ALWAYS_LOG_IF(loggerPtr(), identifier, "frame received after interruption, unmuting");
+ m_interrupted = false;
+ captureStateDidChange();
+ }
+ return;
+ }
+
+ ALWAYS_LOG_IF(loggerPtr(), identifier, "no frame received in ", static_cast<int>(m_captureWatchdogTimer.repeatInterval().value()), " seconds, muting");
+ m_interrupted = true;
+ captureStateDidChange();
+}
+
+void ReplayKitCaptureSource::startCaptureWatchdogTimer()
+{
+ static constexpr Seconds verifyCaptureInterval = 2_s;
+ if (m_captureWatchdogTimer.isActive())
+ return;
+
+ m_captureWatchdogTimer.startRepeating(verifyCaptureInterval);
+ m_lastFrameCount = m_frameCount;
+}
+
+static String screenDeviceUUID()
+{
+ static NeverDestroyed<String> screenID = createCanonicalUUIDString();
+ return screenID;
+}
+
+static CaptureDevice& screenDevice()
+{
+ static NeverDestroyed<CaptureDevice> device = { screenDeviceUUID(), CaptureDevice::DeviceType::Screen, makeString("Screen 1"), emptyString(), true };
+ return device;
+}
+
+std::optional<CaptureDevice> ReplayKitCaptureSource::screenCaptureDeviceWithPersistentID(const String& displayID)
+{
+ if (!isAvailable()) {
+ RELEASE_LOG_ERROR(WebRTC, "ReplayKitCaptureSource::screenCaptureDeviceWithPersistentID: screen capture unavailable");
+ return std::nullopt;
+ }
+
+ if (displayID != screenDeviceUUID()) {
+ RELEASE_LOG_ERROR(WebRTC, "ReplayKitCaptureSource::screenCaptureDeviceWithPersistentID: invalid display ID");
+ return std::nullopt;
+ }
+
+ return screenDevice();
+}
+
+void ReplayKitCaptureSource::screenCaptureDevices(Vector<CaptureDevice>& displays)
+{
+ if (isAvailable())
+ displays.append(screenDevice());
+}
+
+} // namespace WebCore
+
+#endif // ENABLE(MEDIA_STREAM) && PLATFORM(IOS)
Modified: trunk/Source/WebCore/platform/mediastream/mac/CGDisplayStreamCaptureSource.cpp (284294 => 284295)
--- trunk/Source/WebCore/platform/mediastream/mac/CGDisplayStreamCaptureSource.cpp 2021-10-16 00:00:09 UTC (rev 284294)
+++ trunk/Source/WebCore/platform/mediastream/mac/CGDisplayStreamCaptureSource.cpp 2021-10-16 00:34:25 UTC (rev 284295)
@@ -71,9 +71,9 @@
m_isRunning = false;
}
-DisplayCaptureSourceMac::DisplayFrameType CGDisplayStreamCaptureSource::generateFrame()
+DisplayCaptureSourceCocoa::DisplayFrameType CGDisplayStreamCaptureSource::generateFrame()
{
- return RetainPtr { m_currentFrame.ioSurface() };
+ return m_currentFrame;
}
bool CGDisplayStreamCaptureSource::startDisplayStream()
@@ -134,7 +134,7 @@
reinterpret_cast<CGDisplayStreamCaptureSource *>(userInfo)->displayWasReconfigured(display, flags);
}
-void CGDisplayStreamCaptureSource::newFrame(CGDisplayStreamFrameStatus status, DisplaySurface&& newFrame)
+void CGDisplayStreamCaptureSource::newFrame(CGDisplayStreamFrameStatus status, RetainPtr<IOSurfaceRef>&& newFrame)
{
switch (status) {
case kCGDisplayStreamFrameStatusFrameComplete:
@@ -171,7 +171,7 @@
if (!rects || !count)
return;
- RunLoop::main().dispatch([weakThis, status, frame = DisplaySurface { frameSurface }]() mutable {
+ RunLoop::main().dispatch([weakThis, status, frame = retainPtr(frameSurface)]() mutable {
if (!weakThis)
return;
weakThis->newFrame(status, WTFMove(frame));
Modified: trunk/Source/WebCore/platform/mediastream/mac/CGDisplayStreamCaptureSource.h (284294 => 284295)
--- trunk/Source/WebCore/platform/mediastream/mac/CGDisplayStreamCaptureSource.h 2021-10-16 00:00:09 UTC (rev 284294)
+++ trunk/Source/WebCore/platform/mediastream/mac/CGDisplayStreamCaptureSource.h 2021-10-16 00:34:25 UTC (rev 284295)
@@ -27,8 +27,7 @@
#if ENABLE(MEDIA_STREAM) && PLATFORM(MAC)
-#include "DisplayCaptureSourceMac.h"
-#include "IOSurface.h"
+#include "DisplayCaptureSourceCocoa.h"
#include <CoreGraphics/CGDisplayConfiguration.h>
#include <CoreGraphics/CGDisplayStream.h>
#include <wtf/BlockPtr.h>
@@ -40,10 +39,10 @@
namespace WebCore {
-class CGDisplayStreamCaptureSource : public DisplayCaptureSourceMac::Capturer, public CanMakeWeakPtr<CGDisplayStreamCaptureSource> {
+class CGDisplayStreamCaptureSource : public DisplayCaptureSourceCocoa::Capturer, public CanMakeWeakPtr<CGDisplayStreamCaptureSource> {
public:
explicit CGDisplayStreamCaptureSource() = default;
- ~CGDisplayStreamCaptureSource();
+ virtual ~CGDisplayStreamCaptureSource();
protected:
using FrameAvailableCallback = void (^)(CGDisplayStreamFrameStatus, uint64_t, IOSurfaceRef, CGDisplayStreamUpdateRef);
@@ -60,10 +59,10 @@
private:
static void displayReconfigurationCallBack(CGDirectDisplayID, CGDisplayChangeSummaryFlags, void*);
- // DisplayCaptureSourceMac::Capturer
+ // DisplayCaptureSourceCocoa::Capturer
bool start() final;
void stop() final;
- DisplayCaptureSourceMac::DisplayFrameType generateFrame() final;
+ DisplayCaptureSourceCocoa::DisplayFrameType generateFrame() final;
void commitConfiguration(const RealtimeMediaSourceSettings&) final;
void displayWasReconfigured(CGDirectDisplayID, CGDisplayChangeSummaryFlags);
@@ -70,41 +69,9 @@
bool startDisplayStream();
FrameAvailableCallback frameAvailableHandler();
- class DisplaySurface {
- public:
- DisplaySurface() = default;
- explicit DisplaySurface(IOSurfaceRef surface)
- : m_surface(surface)
- {
- if (m_surface)
- IOSurfaceIncrementUseCount(m_surface.get());
- }
+ void newFrame(CGDisplayStreamFrameStatus, RetainPtr<IOSurfaceRef>&&);
- ~DisplaySurface()
- {
- if (m_surface)
- IOSurfaceDecrementUseCount(m_surface.get());
- }
-
- DisplaySurface& operator=(IOSurfaceRef surface)
- {
- if (m_surface)
- IOSurfaceDecrementUseCount(m_surface.get());
- if (surface)
- IOSurfaceIncrementUseCount(surface);
- m_surface = surface;
- return *this;
- }
-
- IOSurfaceRef ioSurface() const { return m_surface.get(); }
-
- private:
- RetainPtr<IOSurfaceRef> m_surface;
- };
-
- void newFrame(CGDisplayStreamFrameStatus, DisplaySurface&&);
-
- DisplaySurface m_currentFrame;
+ RetainPtr<IOSurfaceRef> m_currentFrame;
RetainPtr<CGDisplayStreamRef> m_displayStream;
OSObjectPtr<dispatch_queue_t> m_captureQueue;
BlockPtr<void(CGDisplayStreamFrameStatus, uint64_t, IOSurfaceRef, CGDisplayStreamUpdateRef)> m_frameAvailableHandler;
Modified: trunk/Source/WebCore/platform/mediastream/mac/CGDisplayStreamScreenCaptureSource.h (284294 => 284295)
--- trunk/Source/WebCore/platform/mediastream/mac/CGDisplayStreamScreenCaptureSource.h 2021-10-16 00:00:09 UTC (rev 284294)
+++ trunk/Source/WebCore/platform/mediastream/mac/CGDisplayStreamScreenCaptureSource.h 2021-10-16 00:34:25 UTC (rev 284295)
@@ -41,7 +41,7 @@
class CGDisplayStreamScreenCaptureSource final : public CGDisplayStreamCaptureSource {
public:
- static Expected<UniqueRef<DisplayCaptureSourceMac::Capturer>, String> create(const String&);
+ static Expected<UniqueRef<DisplayCaptureSourceCocoa::Capturer>, String> create(const String&);
explicit CGDisplayStreamScreenCaptureSource(uint32_t);
~CGDisplayStreamScreenCaptureSource() = default;
@@ -51,7 +51,7 @@
private:
- // DisplayCaptureSourceMac::Capturer
+ // DisplayCaptureSourceCocoa::Capturer
CaptureDevice::DeviceType deviceType() const final { return CaptureDevice::DeviceType::Screen; }
RealtimeMediaSourceSettings::DisplaySurfaceType surfaceType() const final { return RealtimeMediaSourceSettings::DisplaySurfaceType::Monitor; }
IntSize intrinsicSize() const final;
@@ -63,38 +63,6 @@
RetainPtr<CGDisplayStreamRef> createDisplayStream(FrameAvailableCallback, dispatch_queue_t) final;
bool checkDisplayStream() final;
- class DisplaySurface {
- public:
- DisplaySurface() = default;
- explicit DisplaySurface(IOSurfaceRef surface)
- : m_surface(surface)
- {
- if (m_surface)
- IOSurfaceIncrementUseCount(m_surface.get());
- }
-
- ~DisplaySurface()
- {
- if (m_surface)
- IOSurfaceDecrementUseCount(m_surface.get());
- }
-
- DisplaySurface& operator=(IOSurfaceRef surface)
- {
- if (m_surface)
- IOSurfaceDecrementUseCount(m_surface.get());
- if (surface)
- IOSurfaceIncrementUseCount(surface);
- m_surface = surface;
- return *this;
- }
-
- IOSurfaceRef ioSurface() const { return m_surface.get(); }
-
- private:
- RetainPtr<IOSurfaceRef> m_surface;
- };
-
RetainPtr<CGDisplayStreamRef> m_displayStream;
uint32_t m_displayID { 0 };
Modified: trunk/Source/WebCore/platform/mediastream/mac/CGDisplayStreamScreenCaptureSource.mm (284294 => 284295)
--- trunk/Source/WebCore/platform/mediastream/mac/CGDisplayStreamScreenCaptureSource.mm 2021-10-16 00:00:09 UTC (rev 284294)
+++ trunk/Source/WebCore/platform/mediastream/mac/CGDisplayStreamScreenCaptureSource.mm 2021-10-16 00:34:25 UTC (rev 284295)
@@ -75,7 +75,7 @@
return std::nullopt;
}
-Expected<UniqueRef<DisplayCaptureSourceMac::Capturer>, String> CGDisplayStreamScreenCaptureSource::create(const String& deviceID)
+Expected<UniqueRef<DisplayCaptureSourceCocoa::Capturer>, String> CGDisplayStreamScreenCaptureSource::create(const String& deviceID)
{
auto displayID = parseInteger<uint32_t>(deviceID);
if (!displayID)
@@ -85,7 +85,7 @@
if (!actualDisplayID)
return makeUnexpected("Invalid display ID"_s);
- return UniqueRef<DisplayCaptureSourceMac::Capturer>(makeUniqueRef<CGDisplayStreamScreenCaptureSource>(actualDisplayID.value()));
+ return UniqueRef<DisplayCaptureSourceCocoa::Capturer>(makeUniqueRef<CGDisplayStreamScreenCaptureSource>(actualDisplayID.value()));
}
CGDisplayStreamScreenCaptureSource::CGDisplayStreamScreenCaptureSource(uint32_t displayID)
Modified: trunk/Source/WebCore/platform/mediastream/mac/DisplayCaptureManagerCocoa.cpp (284294 => 284295)
--- trunk/Source/WebCore/platform/mediastream/mac/DisplayCaptureManagerCocoa.cpp 2021-10-16 00:00:09 UTC (rev 284294)
+++ trunk/Source/WebCore/platform/mediastream/mac/DisplayCaptureManagerCocoa.cpp 2021-10-16 00:34:25 UTC (rev 284295)
@@ -34,10 +34,11 @@
#if PLATFORM(MAC)
#include "CGDisplayStreamScreenCaptureSource.h"
-#include <CoreGraphics/CGDirectDisplay.h>
#endif
-#include "CoreVideoSoftLink.h"
+#if PLATFORM(IOS)
+#include "ReplayKitCaptureSource.h"
+#endif
namespace WebCore {
@@ -61,6 +62,8 @@
{
#if PLATFORM(MAC)
CGDisplayStreamScreenCaptureSource::screenCaptureDevices(m_devices);
+#elif PLATFORM(IOS)
+ ReplayKitCaptureSource::screenCaptureDevices(m_devices);
#endif
}
Deleted: trunk/Source/WebCore/platform/mediastream/mac/DisplayCaptureSourceMac.cpp (284294 => 284295)
--- trunk/Source/WebCore/platform/mediastream/mac/DisplayCaptureSourceMac.cpp 2021-10-16 00:00:09 UTC (rev 284294)
+++ trunk/Source/WebCore/platform/mediastream/mac/DisplayCaptureSourceMac.cpp 2021-10-16 00:34:25 UTC (rev 284295)
@@ -1,274 +0,0 @@
-/*
- * Copyright (C) 2017-2021 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 "DisplayCaptureSourceMac.h"
-
-#if ENABLE(MEDIA_STREAM) && PLATFORM(MAC)
-
-#include "CGDisplayStreamScreenCaptureSource.h"
-#include "Logging.h"
-#include "MediaSampleAVFObjC.h"
-#include "PixelBufferConformerCV.h"
-#include "RealtimeMediaSource.h"
-#include "RealtimeMediaSourceCenter.h"
-#include "RealtimeMediaSourceSettings.h"
-#include "RealtimeVideoUtilities.h"
-#include "RemoteVideoSample.h"
-#include "Timer.h"
-#include <CoreMedia/CMSync.h>
-#include <mach/mach_time.h>
-#include <pal/avfoundation/MediaTimeAVFoundation.h>
-#include <pal/spi/cf/CoreAudioSPI.h>
-#include <pal/spi/cg/CoreGraphicsSPI.h>
-#include <pal/spi/cocoa/IOSurfaceSPI.h>
-#include <sys/time.h>
-#include <wtf/MainThread.h>
-#include <wtf/NeverDestroyed.h>
-
-#include "CoreVideoSoftLink.h"
-#include <pal/cf/CoreMediaSoftLink.h>
-
-namespace WebCore {
-
-CaptureSourceOrError DisplayCaptureSourceMac::create(const CaptureDevice& device, const MediaConstraints* constraints)
-{
- switch (device.type()) {
- case CaptureDevice::DeviceType::Screen:
- return create(CGDisplayStreamScreenCaptureSource::create(device.persistentId()), device, constraints);
- case CaptureDevice::DeviceType::Window:
- case CaptureDevice::DeviceType::Microphone:
- case CaptureDevice::DeviceType::Speaker:
- case CaptureDevice::DeviceType::Camera:
- case CaptureDevice::DeviceType::Unknown:
- ASSERT_NOT_REACHED();
- break;
- }
-
- return { };
-}
-
-CaptureSourceOrError DisplayCaptureSourceMac::create(Expected<UniqueRef<Capturer>, String>&& capturer, const CaptureDevice& device, const MediaConstraints* constraints)
-{
- if (!capturer.has_value())
- return CaptureSourceOrError { WTFMove(capturer.error()) };
-
- auto source = adoptRef(*new DisplayCaptureSourceMac(WTFMove(capturer.value()), String { device.label() }));
- if (constraints) {
- auto result = source->applyConstraints(*constraints);
- if (result)
- return WTFMove(result.value().badConstraint);
- }
-
- return CaptureSourceOrError(WTFMove(source));
-}
-
-DisplayCaptureSourceMac::DisplayCaptureSourceMac(UniqueRef<Capturer>&& capturer, String&& name)
- : RealtimeMediaSource(Type::Video, WTFMove(name))
- , m_capturer(WTFMove(capturer))
- , m_timer(RunLoop::current(), this, &DisplayCaptureSourceMac::emitFrame)
-{
-}
-
-DisplayCaptureSourceMac::~DisplayCaptureSourceMac()
-{
-}
-
-const RealtimeMediaSourceCapabilities& DisplayCaptureSourceMac::capabilities()
-{
- if (!m_capabilities) {
- RealtimeMediaSourceCapabilities capabilities(settings().supportedConstraints());
-
- auto intrinsicSize = m_capturer->intrinsicSize();
- capabilities.setWidth(CapabilityValueOrRange(1, intrinsicSize.width()));
- capabilities.setHeight(CapabilityValueOrRange(1, intrinsicSize.height()));
- capabilities.setFrameRate(CapabilityValueOrRange(.01, 30.0));
-
- m_capabilities = WTFMove(capabilities);
- }
- return m_capabilities.value();
-}
-
-const RealtimeMediaSourceSettings& DisplayCaptureSourceMac::settings()
-{
- if (!m_currentSettings) {
- RealtimeMediaSourceSettings settings;
- settings.setFrameRate(frameRate());
-
- auto size = this->size();
- settings.setWidth(size.width());
- settings.setHeight(size.height());
-
- settings.setDisplaySurface(m_capturer->surfaceType());
- settings.setLogicalSurface(false);
-
- RealtimeMediaSourceSupportedConstraints supportedConstraints;
- supportedConstraints.setSupportsFrameRate(true);
- supportedConstraints.setSupportsWidth(true);
- supportedConstraints.setSupportsHeight(true);
- supportedConstraints.setSupportsDisplaySurface(true);
- supportedConstraints.setSupportsLogicalSurface(true);
-
- settings.setSupportedConstraints(supportedConstraints);
-
- m_currentSettings = WTFMove(settings);
- }
- return m_currentSettings.value();
-}
-
-void DisplayCaptureSourceMac::settingsDidChange(OptionSet<RealtimeMediaSourceSettings::Flag> settings)
-{
- if (settings.contains(RealtimeMediaSourceSettings::Flag::FrameRate) && m_timer.isActive())
- m_timer.startRepeating(1_s / frameRate());
-
- m_currentSettings = { };
-}
-
-void DisplayCaptureSourceMac::startProducingData()
-{
- m_startTime = MonotonicTime::now();
- m_timer.startRepeating(1_s / frameRate());
-
- commitConfiguration();
- if (!m_capturer->start())
- captureFailed();
-}
-
-void DisplayCaptureSourceMac::stopProducingData()
-{
- m_timer.stop();
- m_elapsedTime += MonotonicTime::now() - m_startTime;
- m_startTime = MonotonicTime::nan();
-
- m_capturer->stop();
-}
-
-Seconds DisplayCaptureSourceMac::elapsedTime()
-{
- if (std::isnan(m_startTime))
- return m_elapsedTime;
-
- return m_elapsedTime + (MonotonicTime::now() - m_startTime);
-}
-
-// We keep the aspect ratio of the intrinsic size for the frame size as getDisplayMedia allows max constraints only.
-void DisplayCaptureSourceMac::updateFrameSize()
-{
- auto intrinsicSize = this->intrinsicSize();
-
- auto frameSize = size();
- if (!frameSize.height())
- frameSize.setHeight(intrinsicSize.height());
- if (!frameSize.width())
- frameSize.setWidth(intrinsicSize.width());
-
- auto maxHeight = std::min(frameSize.height(), intrinsicSize.height());
- auto maxWidth = std::min(frameSize.width(), intrinsicSize.width());
-
- auto heightForMaxWidth = maxWidth * intrinsicSize.height() / intrinsicSize.width();
- auto widthForMaxHeight = maxHeight * intrinsicSize.width() / intrinsicSize.height();
-
- if (heightForMaxWidth <= maxHeight) {
- setSize({ maxWidth, heightForMaxWidth });
- return;
- }
- if (widthForMaxHeight <= maxWidth) {
- setSize({ widthForMaxHeight, maxHeight });
- return;
- }
- setSize(intrinsicSize);
-}
-
-void DisplayCaptureSourceMac::emitFrame()
-{
- if (muted())
- return;
-
- if (!m_imageTransferSession)
- m_imageTransferSession = ImageTransferSessionVT::create(preferedPixelBufferFormat());
-
- auto sampleTime = MediaTime::createWithDouble((elapsedTime() + 100_ms).seconds());
-
- auto frame = m_capturer->generateFrame();
- auto imageSize = WTF::switchOn(frame,
- [](RetainPtr<IOSurfaceRef> surface) -> IntSize {
- if (!surface)
- return { };
-
- return IntSize(IOSurfaceGetWidth(surface.get()), IOSurfaceGetHeight(surface.get()));
- },
- [](RefPtr<NativeImage> image) -> IntSize {
- if (!image)
- return { };
-
- return image->size();
- }
- );
-
- if (imageSize.isEmpty())
- return;
-
- if (intrinsicSize() != imageSize) {
- setIntrinsicSize(imageSize);
- updateFrameSize();
- }
-
- auto sample = WTF::switchOn(frame,
- [this, sampleTime](RetainPtr<IOSurfaceRef> surface) -> RefPtr<MediaSample> {
- if (!surface)
- return nullptr;
-
- return m_imageTransferSession->createMediaSample(surface.get(), sampleTime, size());
- },
- [this, sampleTime](RefPtr<NativeImage> image) -> RefPtr<MediaSample> {
- if (!image)
- return nullptr;
-
- return m_imageTransferSession->createMediaSample(image->platformImage().get(), sampleTime, size());
- }
- );
-
- if (!sample) {
- ASSERT_NOT_REACHED();
- return;
- }
-
- videoSampleAvailable(*sample.get());
-}
-
-void DisplayCaptureSourceMac::Capturer::setLogger(const Logger& newLogger, const void* newLogIdentifier)
-{
- m_logger = &newLogger;
- m_logIdentifier = newLogIdentifier;
-}
-
-WTFLogChannel& DisplayCaptureSourceMac::Capturer::logChannel() const
-{
- return LogWebRTC;
-}
-
-} // namespace WebCore
-
-#endif // ENABLE(MEDIA_STREAM) && PLATFORM(MAC)
Deleted: trunk/Source/WebCore/platform/mediastream/mac/DisplayCaptureSourceMac.h (284294 => 284295)
--- trunk/Source/WebCore/platform/mediastream/mac/DisplayCaptureSourceMac.h 2021-10-16 00:00:09 UTC (rev 284294)
+++ trunk/Source/WebCore/platform/mediastream/mac/DisplayCaptureSourceMac.h 2021-10-16 00:34:25 UTC (rev 284295)
@@ -1,119 +0,0 @@
-/*
- * Copyright (C) 2017-2021 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) && PLATFORM(MAC)
-
-#include "CaptureDevice.h"
-#include "ImageTransferSessionVT.h"
-#include "RealtimeMediaSource.h"
-#include <wtf/RefCounted.h>
-#include <wtf/RefPtr.h>
-#include <wtf/RunLoop.h>
-#include <wtf/UniqueRef.h>
-#include <wtf/text/WTFString.h>
-
-typedef struct CGImage *CGImageRef;
-typedef struct __CVBuffer *CVPixelBufferRef;
-typedef struct __IOSurface *IOSurfaceRef;
-
-namespace WTF {
-class MediaTime;
-}
-
-namespace WebCore {
-
-class CaptureDeviceInfo;
-class ImageTransferSessionVT;
-class PixelBufferConformerCV;
-
-class DisplayCaptureSourceMac final : public RealtimeMediaSource {
-public:
- using DisplayFrameType = std::variant<RefPtr<NativeImage>, RetainPtr<IOSurfaceRef>>;
-
- class Capturer : public LoggerHelper {
- WTF_MAKE_FAST_ALLOCATED;
- public:
- virtual ~Capturer() = default;
-
- virtual bool start() = 0;
- virtual void stop() = 0;
- virtual DisplayFrameType generateFrame() = 0;
- virtual CaptureDevice::DeviceType deviceType() const = 0;
- virtual RealtimeMediaSourceSettings::DisplaySurfaceType surfaceType() const = 0;
- virtual void commitConfiguration(const RealtimeMediaSourceSettings&) = 0;
- virtual IntSize intrinsicSize() const = 0;
-
- virtual void setLogger(const Logger&, const void*);
- const Logger* loggerPtr() const { return m_logger.get(); }
- const Logger& logger() const final { ASSERT(m_logger); return *m_logger.get(); }
- const void* logIdentifier() const final { return m_logIdentifier; }
- WTFLogChannel& logChannel() const final;
-
- private:
- RefPtr<const Logger> m_logger;
- const void* m_logIdentifier;
- };
-
- static CaptureSourceOrError create(const CaptureDevice&, const MediaConstraints*);
- static CaptureSourceOrError create(Expected<UniqueRef<Capturer>, String>&&, const CaptureDevice&, const MediaConstraints*);
-
- Seconds elapsedTime();
- void updateFrameSize();
-
-private:
- DisplayCaptureSourceMac(UniqueRef<Capturer>&&, String&& name);
- ~DisplayCaptureSourceMac();
-
- void startProducingData() final;
- void stopProducingData() final;
- void settingsDidChange(OptionSet<RealtimeMediaSourceSettings::Flag>) final;
- bool isCaptureSource() const final { return true; }
- const RealtimeMediaSourceCapabilities& capabilities() final;
- const RealtimeMediaSourceSettings& settings() final;
- CaptureDevice::DeviceType deviceType() const { return m_capturer->deviceType(); }
- void commitConfiguration() final { m_capturer->commitConfiguration(settings()); }
-
- const char* logClassName() const final { return "DisplayCaptureSourceMac"; }
-
- void emitFrame();
-
- UniqueRef<Capturer> m_capturer;
- std::optional<RealtimeMediaSourceCapabilities> m_capabilities;
- std::optional<RealtimeMediaSourceSettings> m_currentSettings;
- RealtimeMediaSourceSupportedConstraints m_supportedConstraints;
-
- MonotonicTime m_startTime { MonotonicTime::nan() };
- Seconds m_elapsedTime { 0_s };
-
- RunLoop::Timer<DisplayCaptureSourceMac> m_timer;
-
- std::unique_ptr<ImageTransferSessionVT> m_imageTransferSession;
-};
-
-} // namespace WebCore
-
-#endif // ENABLE(MEDIA_STREAM) && PLATFORM(MAC)
Modified: trunk/Source/WebCore/platform/mediastream/mac/RealtimeMediaSourceCenterMac.cpp (284294 => 284295)
--- trunk/Source/WebCore/platform/mediastream/mac/RealtimeMediaSourceCenterMac.cpp 2021-10-16 00:00:09 UTC (rev 284294)
+++ trunk/Source/WebCore/platform/mediastream/mac/RealtimeMediaSourceCenterMac.cpp 2021-10-16 00:34:25 UTC (rev 284295)
@@ -36,7 +36,7 @@
#include "AVVideoCaptureSource.h"
#include "CoreAudioCaptureSource.h"
#include "DisplayCaptureManagerCocoa.h"
-#include "DisplayCaptureSourceMac.h"
+#include "DisplayCaptureSourceCocoa.h"
#include "Logging.h"
#include "MediaStreamPrivate.h"
#include <wtf/MainThread.h>
@@ -59,15 +59,7 @@
public:
CaptureSourceOrError createDisplayCaptureSource(const CaptureDevice& device, const MediaConstraints* constraints) final
{
-#if PLATFORM(IOS_FAMILY)
- UNUSED_PARAM(device);
- UNUSED_PARAM(constraints);
-#endif
-#if PLATFORM(MAC)
- return DisplayCaptureSourceMac::create(device, constraints);
-#else
- return { };
-#endif
+ return DisplayCaptureSourceCocoa::create(device, constraints);
}
private:
CaptureDeviceManager& displayCaptureDeviceManager() { return DisplayCaptureManagerCocoa::singleton(); }
Modified: trunk/Source/WebCore/platform/mock/MockRealtimeMediaSourceCenter.cpp (284294 => 284295)
--- trunk/Source/WebCore/platform/mock/MockRealtimeMediaSourceCenter.cpp 2021-10-16 00:00:09 UTC (rev 284294)
+++ trunk/Source/WebCore/platform/mock/MockRealtimeMediaSourceCenter.cpp 2021-10-16 00:34:25 UTC (rev 284295)
@@ -43,7 +43,7 @@
#if PLATFORM(COCOA)
#include "CoreAudioCaptureSource.h"
-#include "DisplayCaptureSourceMac.h"
+#include "DisplayCaptureSourceCocoa.h"
#include "MockRealtimeVideoSourceMac.h"
#endif
@@ -115,7 +115,7 @@
};
#if PLATFORM(MAC)
-class MockDisplayCapturer final : public DisplayCaptureSourceMac::Capturer {
+class MockDisplayCapturer final : public DisplayCaptureSourceCocoa::Capturer {
public:
explicit MockDisplayCapturer(const CaptureDevice&);
@@ -122,7 +122,7 @@
private:
bool start() final;
void stop() final { m_source->stop(); }
- DisplayCaptureSourceMac::DisplayFrameType generateFrame() final;
+ DisplayCaptureSourceCocoa::DisplayFrameType generateFrame() final;
RealtimeMediaSourceSettings::DisplaySurfaceType surfaceType() const final { return RealtimeMediaSourceSettings::DisplaySurfaceType::Monitor; }
void commitConfiguration(const RealtimeMediaSourceSettings&) final;
CaptureDevice::DeviceType deviceType() const final { return CaptureDevice::DeviceType::Screen; }
@@ -152,7 +152,7 @@
m_settings = settings;
}
-DisplayCaptureSourceMac::DisplayFrameType MockDisplayCapturer::generateFrame()
+DisplayCaptureSourceCocoa::DisplayFrameType MockDisplayCapturer::generateFrame()
{
if (auto* imageBuffer = m_source->imageBuffer())
return imageBuffer->copyNativeImage();
@@ -186,7 +186,7 @@
case CaptureDevice::DeviceType::Screen:
case CaptureDevice::DeviceType::Window:
#if PLATFORM(MAC)
- return DisplayCaptureSourceMac::create(UniqueRef<DisplayCaptureSourceMac::Capturer>(makeUniqueRef<MockDisplayCapturer>(device)), device, constraints);
+ return DisplayCaptureSourceCocoa::create(UniqueRef<DisplayCaptureSourceCocoa::Capturer>(makeUniqueRef<MockDisplayCapturer>(device)), device, constraints);
#elif USE(GSTREAMER)
return MockDisplayCaptureSourceGStreamer::create(device, constraints);
#else
Modified: trunk/Source/WebKit/ChangeLog (284294 => 284295)
--- trunk/Source/WebKit/ChangeLog 2021-10-16 00:00:09 UTC (rev 284294)
+++ trunk/Source/WebKit/ChangeLog 2021-10-16 00:34:25 UTC (rev 284295)
@@ -1,3 +1,33 @@
+2021-10-15 Eric Carlson <[email protected]>
+
+ [iOS] Support getDisplayMedia
+ https://bugs.webkit.org/show_bug.cgi?id=231455
+ <rdar://problem/84044495>
+
+ Reviewed by Youenn Fablet and Jer Noble.
+
+ * UIProcess/Cocoa/MediaPermissionUtilities.mm:
+ (WebKit::alertMessageText): Add text for default screen capture prompt.
+ (WebKit::allowButtonText): Ditto.
+ (WebKit::doNotAllowButtonText): Ditto.
+
+ * UIProcess/Cocoa/UIDelegate.mm:
+ (WebKit::UIDelegate::UIClient::decidePolicyForUserMediaPermissionRequest): Call
+ default getDisplayMedia prompt if the delegate doesn't implement the private
+ prompt selector.
+
+ * UIProcess/MediaPermissionUtilities.h:
+ * UIProcess/UserMediaPermissionRequestProxy.cpp:
+ (WebKit::UserMediaPermissionRequestProxy::promptForGetDisplayMedia): New default
+ getDisplayMedia prompt.
+ (WebKit::UserMediaPermissionRequestProxy::promptForGetUserMedia):
+ (WebKit::UserMediaPermissionRequestProxy::doDefaultAction): Call promptForGetDisplayMedia
+ or promptForGetUserMedia according to the request type.
+ (WebKit::UserMediaPermissionRequestProxy::canPromptForGetDisplayMedia):
+ (WebKit::UserMediaPermissionRequestProxy::prompt): Deleted.
+ * UIProcess/UserMediaPermissionRequestProxy.h:
+ (WebKit::UserMediaPermissionRequestProxy::doDefaultAction): Deleted.
+
2021-10-15 Jer Noble <[email protected]>
[iOS] Screen Sharing doesn't switch to AirPlay when <video> enters fullscreen mode
Modified: trunk/Source/WebKit/UIProcess/Cocoa/MediaPermissionUtilities.mm (284294 => 284295)
--- trunk/Source/WebKit/UIProcess/Cocoa/MediaPermissionUtilities.mm 2021-10-16 00:00:09 UTC (rev 284294)
+++ trunk/Source/WebKit/UIProcess/Cocoa/MediaPermissionUtilities.mm 2021-10-16 00:34:25 UTC (rev 284295)
@@ -141,6 +141,8 @@
return [NSString stringWithFormat:WEB_UI_NSSTRING(@"Allow “%@” to use your camera and microphone?", @"Message for user media prompt"), visibleOrigin];
case MediaPermissionReason::Microphone:
return [NSString stringWithFormat:WEB_UI_NSSTRING(@"Allow “%@” to use your microphone?", @"Message for user microphone access prompt"), visibleOrigin];
+ case MediaPermissionReason::ScreenCapture:
+ return [NSString stringWithFormat:WEB_UI_NSSTRING(@"Allow “%@” to observe your screen?", @"Message for screen sharing prompt"), visibleOrigin];
case MediaPermissionReason::DeviceOrientation:
return [NSString stringWithFormat:WEB_UI_NSSTRING(@"“%@” Would Like to Access Motion and Orientation", @"Message for requesting access to the device motion and orientation"), visibleOrigin];
case MediaPermissionReason::Geolocation:
@@ -157,6 +159,8 @@
case MediaPermissionReason::CameraAndMicrophone:
case MediaPermissionReason::Microphone:
return WEB_UI_STRING_KEY(@"Allow", "Allow (usermedia)", @"Allow button title in user media prompt");
+ case MediaPermissionReason::ScreenCapture:
+ return WEB_UI_STRING_KEY(@"Allow", "Allow (screensharing)", @"Allow button title in screen sharing prompt");
case MediaPermissionReason::DeviceOrientation:
return WEB_UI_STRING_KEY(@"Allow", "Allow (device motion and orientation access)", @"Button title in Device Orientation Permission API prompt");
case MediaPermissionReason::Geolocation:
@@ -173,6 +177,8 @@
case MediaPermissionReason::CameraAndMicrophone:
case MediaPermissionReason::Microphone:
return WEB_UI_STRING_KEY(@"Don’t Allow", "Don’t Allow (usermedia)", @"Disallow button title in user media prompt");
+ case MediaPermissionReason::ScreenCapture:
+ return WEB_UI_STRING_KEY(@"Don’t Allow", "Don’t Allow (screensharing)", @"Disallow button title in screen sharing prompt");
case MediaPermissionReason::DeviceOrientation:
return WEB_UI_STRING_KEY(@"Cancel", "Cancel (device motion and orientation access)", @"Button title in Device Orientation Permission API prompt");
case MediaPermissionReason::Geolocation:
Modified: trunk/Source/WebKit/UIProcess/Cocoa/UIDelegate.mm (284294 => 284295)
--- trunk/Source/WebKit/UIProcess/Cocoa/UIDelegate.mm 2021-10-16 00:00:09 UTC (rev 284294)
+++ trunk/Source/WebKit/UIProcess/Cocoa/UIDelegate.mm 2021-10-16 00:34:25 UTC (rev 284295)
@@ -1117,6 +1117,11 @@
return;
}
+ if (request.requiresDisplayCapture() && request.canPromptForGetDisplayMedia()) {
+ request.promptForGetDisplayMedia();
+ return;
+ }
+
// FIXME: Provide a specific delegate for display capture.
if (!request.requiresDisplayCapture() && respondsToRequestMediaCapturePermission) {
auto checker = CompletionHandlerCallChecker::create(delegate, @selector(webView:requestMediaCapturePermissionForOrigin:initiatedByFrame:type:decisionHandler:));
@@ -1127,7 +1132,7 @@
switch (decision) {
case WKPermissionDecisionPrompt:
- protectedRequest->prompt();
+ protectedRequest->promptForGetUserMedia();
break;
case WKPermissionDecisionGrant: {
const String& videoDeviceUID = protectedRequest->requiresVideoCapture() ? protectedRequest->videoDeviceUIDs().first() : String();
Modified: trunk/Source/WebKit/UIProcess/MediaPermissionUtilities.h (284294 => 284295)
--- trunk/Source/WebKit/UIProcess/MediaPermissionUtilities.h 2021-10-16 00:00:09 UTC (rev 284294)
+++ trunk/Source/WebKit/UIProcess/MediaPermissionUtilities.h 2021-10-16 00:34:25 UTC (rev 284295)
@@ -54,7 +54,8 @@
Microphone,
DeviceOrientation,
Geolocation,
- SpeechRecognition
+ SpeechRecognition,
+ ScreenCapture
};
#if PLATFORM(COCOA)
Modified: trunk/Source/WebKit/UIProcess/UserMediaPermissionRequestProxy.cpp (284294 => 284295)
--- trunk/Source/WebKit/UIProcess/UserMediaPermissionRequestProxy.cpp 2021-10-16 00:00:09 UTC (rev 284294)
+++ trunk/Source/WebKit/UIProcess/UserMediaPermissionRequestProxy.cpp 2021-10-16 00:34:25 UTC (rev 284295)
@@ -140,17 +140,29 @@
return values[static_cast<size_t>(enumerationValue)];
}
-void UserMediaPermissionRequestProxy::prompt()
+void UserMediaPermissionRequestProxy::promptForGetDisplayMedia()
{
#if ENABLE(MEDIA_STREAM) && PLATFORM(COCOA)
- ASSERT(m_manager);
- if (!m_manager) {
+ ASSERT(m_manager && canPromptForGetDisplayMedia());
+ if (!m_manager || !canPromptForGetDisplayMedia()) {
deny(UserMediaAccessDenialReason::PermissionDenied);
return;
}
- if (requiresDisplayCapture()) {
- // FIXME: Implement getDisplayMedia prompt, for now deny.
+ alertForPermission(m_manager->page(), MediaPermissionReason::ScreenCapture, topLevelDocumentSecurityOrigin().data(), [this, protectedThis = Ref { *this }](bool granted) {
+ if (!granted)
+ deny(UserMediaAccessDenialReason::PermissionDenied);
+ else
+ allow();
+ });
+#endif
+}
+
+void UserMediaPermissionRequestProxy::promptForGetUserMedia()
+{
+#if ENABLE(MEDIA_STREAM) && PLATFORM(COCOA)
+ ASSERT(m_manager);
+ if (!m_manager) {
deny(UserMediaAccessDenialReason::PermissionDenied);
return;
}
@@ -158,6 +170,7 @@
MediaPermissionReason reason = MediaPermissionReason::Camera;
if (requiresAudioCapture())
reason = requiresVideoCapture() ? MediaPermissionReason::CameraAndMicrophone : MediaPermissionReason::Microphone;
+
alertForPermission(m_manager->page(), reason, topLevelDocumentSecurityOrigin().data(), [this, protectedThis = Ref { *this }](bool granted) {
if (!granted)
deny(UserMediaAccessDenialReason::PermissionDenied);
@@ -164,9 +177,33 @@
else
allow();
});
+#endif
+}
+
+void UserMediaPermissionRequestProxy::doDefaultAction()
+{
+#if ENABLE(MEDIA_STREAM) && PLATFORM(COCOA)
+ if (requiresDisplayCapture()) {
+ if (!canPromptForGetDisplayMedia()) {
+ deny(UserMediaAccessDenialReason::PermissionDenied);
+ return;
+ }
+
+ promptForGetDisplayMedia();
+ } else
+ promptForGetUserMedia();
#else
deny();
#endif
}
+bool UserMediaPermissionRequestProxy::canPromptForGetDisplayMedia()
+{
+#if ENABLE(MEDIA_STREAM) && PLATFORM(IOS)
+ return true;
+#else
+ return false;
+#endif
+}
+
} // namespace WebKit
Modified: trunk/Source/WebKit/UIProcess/UserMediaPermissionRequestProxy.h (284294 => 284295)
--- trunk/Source/WebKit/UIProcess/UserMediaPermissionRequestProxy.h 2021-10-16 00:00:09 UTC (rev 284294)
+++ trunk/Source/WebKit/UIProcess/UserMediaPermissionRequestProxy.h 2021-10-16 00:34:25 UTC (rev 284295)
@@ -45,8 +45,10 @@
void allow(const String& audioDeviceUID, const String& videoDeviceUID);
void allow();
- void prompt();
- void doDefaultAction() { prompt(); }
+ void promptForGetUserMedia();
+ void promptForGetDisplayMedia();
+ bool canPromptForGetDisplayMedia();
+ void doDefaultAction();
enum class UserMediaAccessDenialReason { NoConstraints, UserMediaDisabled, NoCaptureDevices, InvalidConstraint, HardwareError, PermissionDenied, OtherFailure };
void deny(UserMediaAccessDenialReason = UserMediaAccessDenialReason::UserMediaDisabled);