getDisplayMedia is not respecting aspect ratio with max constraints
authoryouenn@apple.com <youenn@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Thu, 23 Apr 2020 08:59:31 +0000 (08:59 +0000)
committeryouenn@apple.com <youenn@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Thu, 23 Apr 2020 08:59:31 +0000 (08:59 +0000)
https://bugs.webkit.org/show_bug.cgi?id=210858

Reviewed by Eric Carlson.

Source/WebCore:

Add computation of exact frame size to respect aspect ratio in DisplayCaptureSourceCocoa::updateFrameSize.
Refactor code to have one source class DisplayCaptureSourceCocoa and specific capturer for screen and window.
This simplifies code and allows reusing DisplayCaptureSourceCocoa with a mock capturer.
Update mock code to use DisplayCaptureSourceCocoa.

Tests: fast/mediastream/getDisplayMedia-max-constraints.html
       fast/mediastream/getDisplayMedia-max-constraints1.html
       fast/mediastream/getDisplayMedia-max-constraints2.html
       fast/mediastream/getDisplayMedia-max-constraints3.html

* SourcesCocoa.txt:
* WebCore.xcodeproj/project.pbxproj:
* platform/mediastream/mac/DisplayCaptureManagerCocoa.cpp:
(WebCore::DisplayCaptureManagerCocoa::updateDisplayCaptureDevices):
(WebCore::DisplayCaptureManagerCocoa::updateWindowCaptureDevices):
(WebCore::DisplayCaptureManagerCocoa::screenCaptureDeviceWithPersistentID):
(WebCore::DisplayCaptureManagerCocoa::windowCaptureDeviceWithPersistentID):
* platform/mediastream/mac/DisplayCaptureSourceCocoa.cpp:
(WebCore::DisplayCaptureSourceCocoa::create):
(WebCore::DisplayCaptureSourceCocoa::DisplayCaptureSourceCocoa):
(WebCore::DisplayCaptureSourceCocoa::~DisplayCaptureSourceCocoa):
(WebCore::DisplayCaptureSourceCocoa::capabilities):
(WebCore::DisplayCaptureSourceCocoa::settings):
(WebCore::DisplayCaptureSourceCocoa::startProducingData):
(WebCore::DisplayCaptureSourceCocoa::stopProducingData):
(WebCore::DisplayCaptureSourceCocoa::updateFrameSize):
(WebCore::DisplayCaptureSourceCocoa::emitFrame):
(WebCore::DisplayCaptureSourceCocoa::Capturer::setLogger):
(WebCore::DisplayCaptureSourceCocoa::Capturer::logChannel const):
* platform/mediastream/mac/DisplayCaptureSourceCocoa.h:
* platform/mediastream/mac/MockRealtimeVideoSourceMac.h:
* platform/mediastream/mac/MockRealtimeVideoSourceMac.mm:
(WebCore::MockRealtimeVideoSourceMac::createForMockDisplayCapturer):
* platform/mediastream/mac/RealtimeMediaSourceCenterMac.cpp:
* platform/mediastream/mac/ScreenDisplayCapturerMac.h: Added.
* platform/mediastream/mac/ScreenDisplayCapturerMac.mm: Added.
(WebCore::ScreenDisplayCapturerMac::create):
(WebCore::ScreenDisplayCapturerMac::ScreenDisplayCapturerMac):
(WebCore::ScreenDisplayCapturerMac::~ScreenDisplayCapturerMac):
(WebCore::ScreenDisplayCapturerMac::createDisplayStream):
(WebCore::ScreenDisplayCapturerMac::start):
(WebCore::ScreenDisplayCapturerMac::stop):
(WebCore::ScreenDisplayCapturerMac::generateFrame):
(WebCore::ScreenDisplayCapturerMac::startDisplayStream):
(WebCore::ScreenDisplayCapturerMac::commitConfiguration):
(WebCore::ScreenDisplayCapturerMac::displayWasReconfigured):
(WebCore::ScreenDisplayCapturerMac::displayReconfigurationCallBack):
(WebCore::ScreenDisplayCapturerMac::newFrame):
(WebCore::ScreenDisplayCapturerMac::screenCaptureDeviceWithPersistentID):
(WebCore::ScreenDisplayCapturerMac::screenCaptureDevices):
* platform/mediastream/mac/WindowDisplayCapturerMac.h: Added.
* platform/mediastream/mac/WindowDisplayCapturerMac.mm: ddedAdded.
(WebCore::WindowDisplayCapturerMac::create):
(WebCore::WindowDisplayCapturerMac::WindowDisplayCapturerMac):
(WebCore::WindowDisplayCapturerMac::windowImage):
(WebCore::WindowDisplayCapturerMac::generateFrame):
(WebCore::WindowDisplayCapturerMac::windowCaptureDeviceWithPersistentID):
(WebCore::WindowDisplayCapturerMac::windowCaptureDevices):
* platform/mock/MockRealtimeMediaSourceCenter.cpp:
(WebCore::MockDisplayCapturer::MockDisplayCapturer):
(WebCore::MockDisplayCapturer::start):
(WebCore::MockDisplayCapturer::generateFrame):
* platform/mock/MockRealtimeVideoSource.h:
(isType):

LayoutTests:

* fast/mediastream/getDisplayMedia-max-constraints-expected.txt: Added.
* fast/mediastream/getDisplayMedia-max-constraints.html: Added.
* fast/mediastream/getDisplayMedia-max-constraints1-expected.txt: Added.
* fast/mediastream/getDisplayMedia-max-constraints1.html: Added.
* fast/mediastream/getDisplayMedia-max-constraints2-expected.txt: Added.
* fast/mediastream/getDisplayMedia-max-constraints2.html: Added.
* fast/mediastream/getDisplayMedia-max-constraints3-expected.txt: Added.
* fast/mediastream/getDisplayMedia-max-constraints3.html: Added.
* fast/mediastream/resources/getDisplayMedia-utils.js: Added.
(async callGetDisplayMedia):
(async waitForHeight):
(async waitForWidth):
* platform/ios/TestExpectations:
Skip new tests as getDisplayMedia is not supported on iOS.

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

28 files changed:
LayoutTests/ChangeLog
LayoutTests/fast/mediastream/constraint-intrinsic-size.html
LayoutTests/fast/mediastream/getDisplayMedia-max-constraints-expected.txt [new file with mode: 0644]
LayoutTests/fast/mediastream/getDisplayMedia-max-constraints.html [new file with mode: 0644]
LayoutTests/fast/mediastream/getDisplayMedia-max-constraints1-expected.txt [new file with mode: 0644]
LayoutTests/fast/mediastream/getDisplayMedia-max-constraints1.html [new file with mode: 0644]
LayoutTests/fast/mediastream/getDisplayMedia-max-constraints2-expected.txt [new file with mode: 0644]
LayoutTests/fast/mediastream/getDisplayMedia-max-constraints2.html [new file with mode: 0644]
LayoutTests/fast/mediastream/getDisplayMedia-max-constraints3-expected.txt [new file with mode: 0644]
LayoutTests/fast/mediastream/getDisplayMedia-max-constraints3.html [new file with mode: 0644]
LayoutTests/fast/mediastream/resources/getDisplayMedia-utils.js [new file with mode: 0644]
LayoutTests/platform/ios/TestExpectations
Source/WebCore/ChangeLog
Source/WebCore/SourcesCocoa.txt
Source/WebCore/WebCore.xcodeproj/project.pbxproj
Source/WebCore/platform/mediastream/RealtimeMediaSourceFactory.h
Source/WebCore/platform/mediastream/mac/DisplayCaptureManagerCocoa.cpp
Source/WebCore/platform/mediastream/mac/DisplayCaptureSourceCocoa.cpp
Source/WebCore/platform/mediastream/mac/DisplayCaptureSourceCocoa.h
Source/WebCore/platform/mediastream/mac/MockRealtimeVideoSourceMac.h
Source/WebCore/platform/mediastream/mac/MockRealtimeVideoSourceMac.mm
Source/WebCore/platform/mediastream/mac/RealtimeMediaSourceCenterMac.cpp
Source/WebCore/platform/mediastream/mac/ScreenDisplayCapturerMac.h [moved from Source/WebCore/platform/mediastream/mac/ScreenDisplayCaptureSourceMac.h with 84% similarity]
Source/WebCore/platform/mediastream/mac/ScreenDisplayCapturerMac.mm [moved from Source/WebCore/platform/mediastream/mac/ScreenDisplayCaptureSourceMac.mm with 71% similarity]
Source/WebCore/platform/mediastream/mac/WindowDisplayCapturerMac.h [moved from Source/WebCore/platform/mediastream/mac/WindowDisplayCaptureSourceMac.h with 81% similarity]
Source/WebCore/platform/mediastream/mac/WindowDisplayCapturerMac.mm [moved from Source/WebCore/platform/mediastream/mac/WindowDisplayCaptureSourceMac.mm with 74% similarity]
Source/WebCore/platform/mock/MockRealtimeMediaSourceCenter.cpp
Source/WebCore/platform/mock/MockRealtimeVideoSource.h

index 1c7f25d..7298b25 100644 (file)
@@ -1,3 +1,25 @@
+2020-04-23  Youenn Fablet  <youenn@apple.com>
+
+        getDisplayMedia is not respecting aspect ratio with max constraints
+        https://bugs.webkit.org/show_bug.cgi?id=210858
+
+        Reviewed by Eric Carlson.
+
+        * fast/mediastream/getDisplayMedia-max-constraints-expected.txt: Added.
+        * fast/mediastream/getDisplayMedia-max-constraints.html: Added.
+        * fast/mediastream/getDisplayMedia-max-constraints1-expected.txt: Added.
+        * fast/mediastream/getDisplayMedia-max-constraints1.html: Added.
+        * fast/mediastream/getDisplayMedia-max-constraints2-expected.txt: Added.
+        * fast/mediastream/getDisplayMedia-max-constraints2.html: Added.
+        * fast/mediastream/getDisplayMedia-max-constraints3-expected.txt: Added.
+        * fast/mediastream/getDisplayMedia-max-constraints3.html: Added.
+        * fast/mediastream/resources/getDisplayMedia-utils.js: Added.
+        (async callGetDisplayMedia):
+        (async waitForHeight):
+        (async waitForWidth):
+        * platform/ios/TestExpectations:
+        Skip new tests as getDisplayMedia is not supported on iOS.
+
 2020-04-23  Diego Pino Garcia  <dpino@igalia.com>
 
         [GTK][WPE] Gardening, update baselines and test expectations
index 566cb11..1ae0879 100644 (file)
@@ -5,22 +5,11 @@
         <title>video track width and height should be set correctly when only one constraint is passed to getDisplayMedia</title>
         <script src="../../resources/testharness.js"></script>
         <script src="../../resources/testharnessreport.js"></script>
+        <script src="resources/getDisplayMedia-utils.js"></script>
     </head>
     <body>
 
         <script>
-            if (window.internals)
-                window.internals.settings.setScreenCaptureEnabled(true);
-
-            function callGetDisplayMedia(options)
-            {
-                let promise;
-                window.internals.withUserGesture(() => {
-                    promise = navigator.mediaDevices.getDisplayMedia(options);
-                });
-                return promise;
-            }
-
             let defaultWidth;
             let defaultHeight;
             promise_test(async () => {
diff --git a/LayoutTests/fast/mediastream/getDisplayMedia-max-constraints-expected.txt b/LayoutTests/fast/mediastream/getDisplayMedia-max-constraints-expected.txt
new file mode 100644 (file)
index 0000000..888087f
--- /dev/null
@@ -0,0 +1,6 @@
+
+PASS setup 
+PASS Maximize the width if max height is too big 
+PASS Maximize the height if max width is too big 
+PASS No effect of the max values if they are too big 
+
diff --git a/LayoutTests/fast/mediastream/getDisplayMedia-max-constraints.html b/LayoutTests/fast/mediastream/getDisplayMedia-max-constraints.html
new file mode 100644 (file)
index 0000000..e72945d
--- /dev/null
@@ -0,0 +1,93 @@
+<!doctype html>
+<html>
+    <head>
+        <meta charset="utf-8">
+        <title>getDisplayMedia track support of max constraints</title>
+        <script src="../../resources/testharness.js"></script>
+        <script src="../../resources/testharnessreport.js"></script>
+    </head>
+    <body>
+
+        <script>
+            if (window.internals)
+                window.internals.settings.setScreenCaptureEnabled(true);
+
+            async function callGetDisplayMedia(options)
+            {
+                let promise;
+                window.internals.withUserGesture(() => {
+                    promise = navigator.mediaDevices.getDisplayMedia(options);
+                });
+                const stream = await promise; 
+                const track = stream.getVideoTracks()[0];
+
+                // getSettings is not computing the correct parameters right away. We should probably fix this.
+                while (true) {
+                    const settings = track.getSettings();
+                    if (settings.width && settings.height)
+                        break;
+                    await new Promise(resolve => setTimeout(resolve, 50));
+                }
+                return stream;
+            }
+
+            // getSettings is not computing the correct parameters right away. We should probably fix this.
+            async function waitForHeight(track, value) {
+                while (true) {
+                    const settings = track.getSettings();
+                    if (settings.height === value)
+                        break;
+                    await new Promise(resolve => setTimeout(resolve, 50));
+                }
+            }
+
+            // getSettings is not computing the correct parameters right away. We should probably fix this.
+            async function waitForWidth(track, value) {
+                while (true) {
+                    const settings = track.getSettings();
+                    if (settings.width === value)
+                        break;
+                    await new Promise(resolve => setTimeout(resolve, 50));
+                }
+            }
+
+            let defaultWidth;
+            let defaultHeight;
+            promise_test(async () => {
+                stream = await callGetDisplayMedia({ video: true });
+                let settings = stream.getVideoTracks()[0].getSettings();
+                defaultWidth = settings.width;
+                defaultHeight = settings.height;
+            }, "setup");
+            
+            promise_test(async (test) => {
+                const stream = await callGetDisplayMedia({ video: { height: { max: 500 }, width : { max : 500 } } });
+
+                const expectedHeight =Math.floor(500 * (defaultHeight / defaultWidth)) 
+                await waitForHeight(stream.getVideoTracks()[0], expectedHeight);
+
+                const settings = stream.getVideoTracks()[0].getSettings()
+                assert_equals(settings.width, 500);
+            }, "Maximize the width if max height is too big");
+
+            promise_test(async (test) => {
+                const stream = await callGetDisplayMedia({ video: { height: { max: 100 }, width : { max : 500 } } });
+
+                const expectedWidth = Math.floor(100 * (defaultWidth / defaultHeight)) 
+                await waitForWidth(stream.getVideoTracks()[0], expectedWidth);
+
+                const settings = stream.getVideoTracks()[0].getSettings()
+                assert_equals(settings.height, 100);
+            }, "Maximize the height if max width is too big");
+
+            promise_test(async (test) => {
+                const stream = await callGetDisplayMedia({ video: { height: { max: 500000 }, width : { max : 500000 } } });
+
+                await waitForHeight(stream.getVideoTracks()[0], defaultHeight);
+
+                const settings = stream.getVideoTracks()[0].getSettings()
+                assert_equals(settings.width, defaultWidth);
+            }, "No effect of the max values if they are too big");
+        </script>
+    </body>
+</html>
diff --git a/LayoutTests/fast/mediastream/getDisplayMedia-max-constraints1-expected.txt b/LayoutTests/fast/mediastream/getDisplayMedia-max-constraints1-expected.txt
new file mode 100644 (file)
index 0000000..c47bde6
--- /dev/null
@@ -0,0 +1,4 @@
+
+PASS setup 
+PASS Maximize the width if max height is too big 
+
diff --git a/LayoutTests/fast/mediastream/getDisplayMedia-max-constraints1.html b/LayoutTests/fast/mediastream/getDisplayMedia-max-constraints1.html
new file mode 100644 (file)
index 0000000..6ee7db8
--- /dev/null
@@ -0,0 +1,32 @@
+<!doctype html>
+<html>
+    <head>
+        <meta charset="utf-8">
+        <title>getDisplayMedia track support of max constraints</title>
+        <script src="../../resources/testharness.js"></script>
+        <script src="../../resources/testharnessreport.js"></script>
+        <script src="resources/getDisplayMedia-utils.js"></script>
+    </head>
+    <body>
+        <script>
+let defaultWidth;
+let defaultHeight;
+promise_test(async () => {
+    stream = await callGetDisplayMedia({ video: true });
+    let settings = stream.getVideoTracks()[0].getSettings();
+    defaultWidth = settings.width;
+    defaultHeight = settings.height;
+}, "setup");
+
+promise_test(async (test) => {
+    const stream = await callGetDisplayMedia({ video: { height: { max: 500 }, width : { max : 500 } } });
+
+    const expectedHeight =Math.floor(500 * (defaultHeight / defaultWidth)) 
+    await waitForHeight(stream.getVideoTracks()[0], expectedHeight);
+
+    const settings = stream.getVideoTracks()[0].getSettings()
+    assert_equals(settings.width, 500);
+}, "Maximize the width if max height is too big");
+        </script>
+    </body>
+</html>
diff --git a/LayoutTests/fast/mediastream/getDisplayMedia-max-constraints2-expected.txt b/LayoutTests/fast/mediastream/getDisplayMedia-max-constraints2-expected.txt
new file mode 100644 (file)
index 0000000..488d778
--- /dev/null
@@ -0,0 +1,4 @@
+
+PASS setup 
+PASS Maximize the height if max width is too big 
+
diff --git a/LayoutTests/fast/mediastream/getDisplayMedia-max-constraints2.html b/LayoutTests/fast/mediastream/getDisplayMedia-max-constraints2.html
new file mode 100644 (file)
index 0000000..85a199e
--- /dev/null
@@ -0,0 +1,32 @@
+<!doctype html>
+<html>
+    <head>
+        <meta charset="utf-8">
+        <title>getDisplayMedia track support of max constraints</title>
+        <script src="../../resources/testharness.js"></script>
+        <script src="../../resources/testharnessreport.js"></script>
+        <script src="resources/getDisplayMedia-utils.js"></script>
+    </head>
+    <body>
+        <script>
+let defaultWidth;
+let defaultHeight;
+promise_test(async () => {
+    stream = await callGetDisplayMedia({ video: true });
+    let settings = stream.getVideoTracks()[0].getSettings();
+    defaultWidth = settings.width;
+    defaultHeight = settings.height;
+}, "setup");
+
+promise_test(async (test) => {
+    const stream = await callGetDisplayMedia({ video: { height: { max: 100 }, width : { max : 500 } } });
+
+    const expectedWidth = Math.floor(100 * (defaultWidth / defaultHeight)) 
+    await waitForWidth(stream.getVideoTracks()[0], expectedWidth);
+
+    const settings = stream.getVideoTracks()[0].getSettings()
+    assert_equals(settings.height, 100);
+}, "Maximize the height if max width is too big");
+        </script>
+    </body>
+</html>
diff --git a/LayoutTests/fast/mediastream/getDisplayMedia-max-constraints3-expected.txt b/LayoutTests/fast/mediastream/getDisplayMedia-max-constraints3-expected.txt
new file mode 100644 (file)
index 0000000..d40abe8
--- /dev/null
@@ -0,0 +1,4 @@
+
+PASS setup 
+PASS No effect of the max values if they are too big 
+
diff --git a/LayoutTests/fast/mediastream/getDisplayMedia-max-constraints3.html b/LayoutTests/fast/mediastream/getDisplayMedia-max-constraints3.html
new file mode 100644 (file)
index 0000000..c5e5e3a
--- /dev/null
@@ -0,0 +1,31 @@
+<!doctype html>
+<html>
+    <head>
+        <meta charset="utf-8">
+        <title>getDisplayMedia track support of max constraints</title>
+        <script src="../../resources/testharness.js"></script>
+        <script src="../../resources/testharnessreport.js"></script>
+        <script src="resources/getDisplayMedia-utils.js"></script>
+    </head>
+    <body>
+        <script>
+let defaultWidth;
+let defaultHeight;
+promise_test(async () => {
+    stream = await callGetDisplayMedia({ video: true });
+    let settings = stream.getVideoTracks()[0].getSettings();
+    defaultWidth = settings.width;
+    defaultHeight = settings.height;
+}, "setup");
+
+promise_test(async (test) => {
+    const stream = await callGetDisplayMedia({ video: { height: { max: 500000 }, width : { max : 500000 } } });
+
+    await waitForHeight(stream.getVideoTracks()[0], defaultHeight);
+
+    const settings = stream.getVideoTracks()[0].getSettings()
+    assert_equals(settings.width, defaultWidth);
+}, "No effect of the max values if they are too big");
+        </script>
+    </body>
+</html>
diff --git a/LayoutTests/fast/mediastream/resources/getDisplayMedia-utils.js b/LayoutTests/fast/mediastream/resources/getDisplayMedia-utils.js
new file mode 100644 (file)
index 0000000..8b46c37
--- /dev/null
@@ -0,0 +1,39 @@
+if (window.internals)
+    window.internals.settings.setScreenCaptureEnabled(true);
+
+async function callGetDisplayMedia(options)
+{
+    let promise;
+    window.internals.withUserGesture(() => {
+        promise = navigator.mediaDevices.getDisplayMedia(options);
+    });
+    const stream = await promise; 
+    const track = stream.getVideoTracks()[0];
+
+    // getSettings is not computing the correct parameters right away. We should probably fix this.
+    while (true) {
+        const settings = track.getSettings();
+        if (settings.width && settings.height)
+            break;
+        await new Promise(resolve => setTimeout(resolve, 50));
+    }
+    return stream;
+}
+
+async function waitForHeight(track, value) {
+    while (true) {
+        const settings = track.getSettings();
+        if (settings.height === value)
+            break;
+        await new Promise(resolve => setTimeout(resolve, 50));
+    }
+}
+
+async function waitForWidth(track, value) {
+    while (true) {
+        const settings = track.getSettings();
+        if (settings.width === value)
+            break;
+        await new Promise(resolve => setTimeout(resolve, 50));
+    }
+}
index 252da9f..cf6fc77 100644 (file)
@@ -2895,6 +2895,9 @@ fast/mediastream/RTCPeerConnection-stats.html [ Skip ]
 
 # screen capture not supported on iOS.
 fast/mediastream/screencapture-user-gesture.html [ Skip ]
+fast/mediastream/getDisplayMedia-max-constraints1.html [ Skip ]
+fast/mediastream/getDisplayMedia-max-constraints2.html [ Skip ]
+fast/mediastream/getDisplayMedia-max-constraints3.html [ Skip ]
 
 webkit.org/b/177401 webrtc/captureCanvas-webrtc.html [ Pass Timeout Failure ]
 
index 3b91629..f46ccd9 100644 (file)
@@ -1,3 +1,75 @@
+2020-04-23  Youenn Fablet  <youenn@apple.com>
+
+        getDisplayMedia is not respecting aspect ratio with max constraints
+        https://bugs.webkit.org/show_bug.cgi?id=210858
+
+        Reviewed by Eric Carlson.
+
+        Add computation of exact frame size to respect aspect ratio in DisplayCaptureSourceCocoa::updateFrameSize.
+        Refactor code to have one source class DisplayCaptureSourceCocoa and specific capturer for screen and window.
+        This simplifies code and allows reusing DisplayCaptureSourceCocoa with a mock capturer.
+        Update mock code to use DisplayCaptureSourceCocoa.
+
+        Tests: fast/mediastream/getDisplayMedia-max-constraints.html
+               fast/mediastream/getDisplayMedia-max-constraints1.html
+               fast/mediastream/getDisplayMedia-max-constraints2.html
+               fast/mediastream/getDisplayMedia-max-constraints3.html
+
+        * SourcesCocoa.txt:
+        * WebCore.xcodeproj/project.pbxproj:
+        * platform/mediastream/mac/DisplayCaptureManagerCocoa.cpp:
+        (WebCore::DisplayCaptureManagerCocoa::updateDisplayCaptureDevices):
+        (WebCore::DisplayCaptureManagerCocoa::updateWindowCaptureDevices):
+        (WebCore::DisplayCaptureManagerCocoa::screenCaptureDeviceWithPersistentID):
+        (WebCore::DisplayCaptureManagerCocoa::windowCaptureDeviceWithPersistentID):
+        * platform/mediastream/mac/DisplayCaptureSourceCocoa.cpp:
+        (WebCore::DisplayCaptureSourceCocoa::create):
+        (WebCore::DisplayCaptureSourceCocoa::DisplayCaptureSourceCocoa):
+        (WebCore::DisplayCaptureSourceCocoa::~DisplayCaptureSourceCocoa):
+        (WebCore::DisplayCaptureSourceCocoa::capabilities):
+        (WebCore::DisplayCaptureSourceCocoa::settings):
+        (WebCore::DisplayCaptureSourceCocoa::startProducingData):
+        (WebCore::DisplayCaptureSourceCocoa::stopProducingData):
+        (WebCore::DisplayCaptureSourceCocoa::updateFrameSize):
+        (WebCore::DisplayCaptureSourceCocoa::emitFrame):
+        (WebCore::DisplayCaptureSourceCocoa::Capturer::setLogger):
+        (WebCore::DisplayCaptureSourceCocoa::Capturer::logChannel const):
+        * platform/mediastream/mac/DisplayCaptureSourceCocoa.h:
+        * platform/mediastream/mac/MockRealtimeVideoSourceMac.h:
+        * platform/mediastream/mac/MockRealtimeVideoSourceMac.mm:
+        (WebCore::MockRealtimeVideoSourceMac::createForMockDisplayCapturer):
+        * platform/mediastream/mac/RealtimeMediaSourceCenterMac.cpp:
+        * platform/mediastream/mac/ScreenDisplayCapturerMac.h: Added.
+        * platform/mediastream/mac/ScreenDisplayCapturerMac.mm: Added.
+        (WebCore::ScreenDisplayCapturerMac::create):
+        (WebCore::ScreenDisplayCapturerMac::ScreenDisplayCapturerMac):
+        (WebCore::ScreenDisplayCapturerMac::~ScreenDisplayCapturerMac):
+        (WebCore::ScreenDisplayCapturerMac::createDisplayStream):
+        (WebCore::ScreenDisplayCapturerMac::start):
+        (WebCore::ScreenDisplayCapturerMac::stop):
+        (WebCore::ScreenDisplayCapturerMac::generateFrame):
+        (WebCore::ScreenDisplayCapturerMac::startDisplayStream):
+        (WebCore::ScreenDisplayCapturerMac::commitConfiguration):
+        (WebCore::ScreenDisplayCapturerMac::displayWasReconfigured):
+        (WebCore::ScreenDisplayCapturerMac::displayReconfigurationCallBack):
+        (WebCore::ScreenDisplayCapturerMac::newFrame):
+        (WebCore::ScreenDisplayCapturerMac::screenCaptureDeviceWithPersistentID):
+        (WebCore::ScreenDisplayCapturerMac::screenCaptureDevices):
+        * platform/mediastream/mac/WindowDisplayCapturerMac.h: Added.
+        * platform/mediastream/mac/WindowDisplayCapturerMac.mm: ddedAdded.
+        (WebCore::WindowDisplayCapturerMac::create):
+        (WebCore::WindowDisplayCapturerMac::WindowDisplayCapturerMac):
+        (WebCore::WindowDisplayCapturerMac::windowImage):
+        (WebCore::WindowDisplayCapturerMac::generateFrame):
+        (WebCore::WindowDisplayCapturerMac::windowCaptureDeviceWithPersistentID):
+        (WebCore::WindowDisplayCapturerMac::windowCaptureDevices):
+        * platform/mock/MockRealtimeMediaSourceCenter.cpp:
+        (WebCore::MockDisplayCapturer::MockDisplayCapturer):
+        (WebCore::MockDisplayCapturer::start):
+        (WebCore::MockDisplayCapturer::generateFrame):
+        * platform/mock/MockRealtimeVideoSource.h:
+        (isType):
+
 2020-04-22  Simon Fraser  <simon.fraser@apple.com>
 
         Make it possible to eagerly apply scrolling tree state from the main thread
index 23dead9..d385ed3 100644 (file)
@@ -570,8 +570,8 @@ platform/mediastream/mac/RealtimeMediaSourceCenterMac.mm
 platform/mediastream/mac/RealtimeOutgoingAudioSourceCocoa.cpp
 platform/mediastream/mac/RealtimeOutgoingVideoSourceCocoa.cpp
 platform/mediastream/mac/RealtimeVideoUtilities.mm
-platform/mediastream/mac/ScreenDisplayCaptureSourceMac.mm
-platform/mediastream/mac/WindowDisplayCaptureSourceMac.mm
+platform/mediastream/mac/ScreenDisplayCapturerMac.mm
+platform/mediastream/mac/WindowDisplayCapturerMac.mm
 
 platform/audio/mac/AudioSampleDataSource.mm
 
index 19fc5f6..511256c 100644 (file)
                07C1C0E51BFB60ED00BD2256 /* RealtimeMediaSourceSupportedConstraints.h in Headers */ = {isa = PBXBuildFile; fileRef = 07C1C0E41BFB60ED00BD2256 /* RealtimeMediaSourceSupportedConstraints.h */; settings = {ATTRIBUTES = (Private, ); }; };
                07CE77D516712A6A00C55A47 /* InbandTextTrackPrivateClient.h in Headers */ = {isa = PBXBuildFile; fileRef = 07CE77D416712A6A00C55A47 /* InbandTextTrackPrivateClient.h */; settings = {ATTRIBUTES = (Private, ); }; };
                07D12F5C23DE543F0080997D /* ISOVTTCue.h in Headers */ = {isa = PBXBuildFile; fileRef = CD871C651FB52B6700F0B965 /* ISOVTTCue.h */; settings = {ATTRIBUTES = (Private, ); }; };
-               07D60928214C5BFD00E7396C /* WindowDisplayCaptureSourceMac.h in Headers */ = {isa = PBXBuildFile; fileRef = 07D60926214C5BFC00E7396C /* WindowDisplayCaptureSourceMac.h */; };
                07D637401BB0B11300256CE9 /* WebAudioSourceProviderAVFObjC.h in Headers */ = {isa = PBXBuildFile; fileRef = 07D6373E1BB0B11300256CE9 /* WebAudioSourceProviderAVFObjC.h */; settings = {ATTRIBUTES = (Private, ); }; };
                07D6A4F41BED5F8800174146 /* MockRealtimeAudioSource.h in Headers */ = {isa = PBXBuildFile; fileRef = 07D6A4F21BED5F8800174146 /* MockRealtimeAudioSource.h */; settings = {ATTRIBUTES = (Private, ); }; };
                07D6A4F81BF2307D00174146 /* AudioTrackPrivateMediaStream.h in Headers */ = {isa = PBXBuildFile; fileRef = 07D6A4F61BF2307D00174146 /* AudioTrackPrivateMediaStream.h */; };
                0709D7911AE5557E004E42F8 /* WebMediaSessionManagerMac.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = WebMediaSessionManagerMac.h; sourceTree = "<group>"; };
                0709D7941AE55A29004E42F8 /* WebMediaSessionManagerClient.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = WebMediaSessionManagerClient.h; sourceTree = "<group>"; };
                0709FC4D1025DEE30059CDBA /* AccessibilitySlider.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = AccessibilitySlider.h; sourceTree = "<group>"; };
-               070A9F5E1FFECC70003DF649 /* ScreenDisplayCaptureSourceMac.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ScreenDisplayCaptureSourceMac.h; sourceTree = "<group>"; };
-               070A9F601FFECC71003DF649 /* ScreenDisplayCaptureSourceMac.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = ScreenDisplayCaptureSourceMac.mm; sourceTree = "<group>"; };
                070DD8F50F01868000727DEB /* mediaControls.css */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = mediaControls.css; sourceTree = "<group>"; };
                070E09181875ED93003A1D3C /* PlatformMediaSession.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PlatformMediaSession.h; sourceTree = "<group>"; };
                070E091A1875EF71003A1D3C /* PlatformMediaSession.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = PlatformMediaSession.cpp; sourceTree = "<group>"; };
                07C8AD111D073D630087C5CE /* AVAssetMIMETypeCache.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = AVAssetMIMETypeCache.mm; sourceTree = "<group>"; };
                07C8AD121D073D630087C5CE /* AVAssetMIMETypeCache.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = AVAssetMIMETypeCache.h; sourceTree = "<group>"; };
                07CE77D416712A6A00C55A47 /* InbandTextTrackPrivateClient.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = InbandTextTrackPrivateClient.h; sourceTree = "<group>"; };
-               07D60924214C5BFB00E7396C /* WindowDisplayCaptureSourceMac.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = WindowDisplayCaptureSourceMac.mm; sourceTree = "<group>"; };
-               07D60926214C5BFC00E7396C /* WindowDisplayCaptureSourceMac.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = WindowDisplayCaptureSourceMac.h; sourceTree = "<group>"; };
                07D6373E1BB0B11300256CE9 /* WebAudioSourceProviderAVFObjC.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = WebAudioSourceProviderAVFObjC.h; sourceTree = "<group>"; };
                07D6373F1BB0B11300256CE9 /* WebAudioSourceProviderAVFObjC.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = WebAudioSourceProviderAVFObjC.mm; sourceTree = "<group>"; };
                07D6A4F11BED5F8800174146 /* MockRealtimeAudioSource.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = MockRealtimeAudioSource.cpp; sourceTree = "<group>"; };
                416D759F20C6441300D02D2C /* NetworkLoadInformation.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = NetworkLoadInformation.h; sourceTree = "<group>"; };
                416E0B37209BC3C2004A95D9 /* FetchIdentifier.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = FetchIdentifier.h; sourceTree = "<group>"; };
                416E29A5102FA962007FC14E /* WorkerReportingProxy.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = WorkerReportingProxy.h; sourceTree = "<group>"; };
+               416F807924509F3200B68F02 /* WindowDisplayCapturerMac.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = WindowDisplayCapturerMac.h; sourceTree = "<group>"; };
+               416F807A24509F3200B68F02 /* ScreenDisplayCapturerMac.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = ScreenDisplayCapturerMac.mm; sourceTree = "<group>"; };
+               416F807B24509F3300B68F02 /* WindowDisplayCapturerMac.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = WindowDisplayCapturerMac.mm; sourceTree = "<group>"; };
+               416F807C24509F3300B68F02 /* ScreenDisplayCapturerMac.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ScreenDisplayCapturerMac.h; sourceTree = "<group>"; };
                416FD25D240EE1AE006661D8 /* NowPlayingInfo.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = NowPlayingInfo.h; sourceTree = "<group>"; };
                4170A2E91D8C0CC000318452 /* JSDOMWrapper.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = JSDOMWrapper.cpp; sourceTree = "<group>"; };
                417253A81354BBBC00360F2A /* MediaControlTextTrackContainerElement.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = MediaControlTextTrackContainerElement.cpp; sourceTree = "<group>"; };
                                419242472127B7CC00634FCF /* RealtimeOutgoingVideoSourceCocoa.mm */,
                                41D1938F2152C561006F14CA /* RealtimeVideoUtilities.h */,
                                4158649F23BF7B9300A0A61E /* RealtimeVideoUtilities.mm */,
-                               070A9F5E1FFECC70003DF649 /* ScreenDisplayCaptureSourceMac.h */,
-                               070A9F601FFECC71003DF649 /* ScreenDisplayCaptureSourceMac.mm */,
+                               416F807C24509F3300B68F02 /* ScreenDisplayCapturerMac.h */,
+                               416F807A24509F3200B68F02 /* ScreenDisplayCapturerMac.mm */,
                                07D6373E1BB0B11300256CE9 /* WebAudioSourceProviderAVFObjC.h */,
                                07D6373F1BB0B11300256CE9 /* WebAudioSourceProviderAVFObjC.mm */,
-                               07D60926214C5BFC00E7396C /* WindowDisplayCaptureSourceMac.h */,
-                               07D60924214C5BFB00E7396C /* WindowDisplayCaptureSourceMac.mm */,
+                               416F807924509F3200B68F02 /* WindowDisplayCapturerMac.h */,
+                               416F807B24509F3300B68F02 /* WindowDisplayCapturerMac.mm */,
                        );
                        path = mac;
                        sourceTree = "<group>";
                                1411DCB1164C39A800D49BC1 /* WidthCache.h in Headers */,
                                939B02EF0EA2DBC400C54570 /* WidthIterator.h in Headers */,
                                0F15ED5C1B7EC7C500EDDFEB /* WillChangeData.h in Headers */,
-                               07D60928214C5BFD00E7396C /* WindowDisplayCaptureSourceMac.h in Headers */,
                                9B27FC60234D9ADB00394A46 /* WindowEventLoop.h in Headers */,
                                BC8243E90D0CFD7500460C8F /* WindowFeatures.h in Headers */,
                                7E99AF530B13846468FB01A5 /* WindowFocusAllowedIndicator.h in Headers */,
index bb498c3..303441d 100644 (file)
@@ -89,7 +89,11 @@ protected:
     VideoCaptureFactory() = default;
 };
 
-class DisplayCaptureFactory {
+class DisplayCaptureFactory
+#if PLATFORM(IOS_FAMILY)
+    : public SingleSourceFactory
+#endif
+{
 public:
     virtual ~DisplayCaptureFactory() = default;
     virtual CaptureSourceOrError createDisplayCaptureSource(const CaptureDevice&, const MediaConstraints*) = 0;
index 294c18c..8ee3644 100644 (file)
@@ -33,8 +33,8 @@
 #include <wtf/NeverDestroyed.h>
 
 #if PLATFORM(MAC)
-#include "ScreenDisplayCaptureSourceMac.h"
-#include "WindowDisplayCaptureSourceMac.h"
+#include "ScreenDisplayCapturerMac.h"
+#include "WindowDisplayCapturerMac.h"
 #include <CoreGraphics/CGDirectDisplay.h>
 #endif
 
@@ -61,21 +61,21 @@ const Vector<CaptureDevice>& DisplayCaptureManagerCocoa::captureDevices()
 void DisplayCaptureManagerCocoa::updateDisplayCaptureDevices()
 {
 #if PLATFORM(MAC)
-    ScreenDisplayCaptureSourceMac::screenCaptureDevices(m_devices);
+    ScreenDisplayCapturerMac::screenCaptureDevices(m_devices);
 #endif
 }
 
 void DisplayCaptureManagerCocoa::updateWindowCaptureDevices()
 {
 #if PLATFORM(MAC)
-    WindowDisplayCaptureSourceMac::windowCaptureDevices(m_devices);
+    WindowDisplayCapturerMac::windowCaptureDevices(m_devices);
 #endif
 }
 
 Optional<CaptureDevice> DisplayCaptureManagerCocoa::screenCaptureDeviceWithPersistentID(const String& deviceID)
 {
 #if PLATFORM(MAC)
-    return ScreenDisplayCaptureSourceMac::screenCaptureDeviceWithPersistentID(deviceID);
+    return ScreenDisplayCapturerMac::screenCaptureDeviceWithPersistentID(deviceID);
 #else
     UNUSED_PARAM(deviceID);
     return WTF::nullopt;
@@ -85,7 +85,7 @@ Optional<CaptureDevice> DisplayCaptureManagerCocoa::screenCaptureDeviceWithPersi
 Optional<CaptureDevice> DisplayCaptureManagerCocoa::windowCaptureDeviceWithPersistentID(const String& deviceID)
 {
 #if PLATFORM(MAC)
-    return WindowDisplayCaptureSourceMac::windowCaptureDeviceWithPersistentID(deviceID);
+    return WindowDisplayCapturerMac::windowCaptureDeviceWithPersistentID(deviceID);
 #else
     UNUSED_PARAM(deviceID);
     return WTF::nullopt;
index 18cfe1c..8318323 100644 (file)
 namespace WebCore {
 using namespace PAL;
 
-DisplayCaptureSourceCocoa::DisplayCaptureSourceCocoa(String&& name)
+CaptureSourceOrError DisplayCaptureSourceCocoa::create(const CaptureDevice& device, const MediaConstraints* constraints)
+{
+#if PLATFORM(MAC)
+    switch (device.type()) {
+    case CaptureDevice::DeviceType::Screen:
+        return create(ScreenDisplayCapturerMac::create(device.persistentId()), device, constraints);
+    case CaptureDevice::DeviceType::Window:
+        return create(WindowDisplayCapturerMac::create(device.persistentId()), device, constraints);
+    case CaptureDevice::DeviceType::Microphone:
+    case CaptureDevice::DeviceType::Camera:
+    case CaptureDevice::DeviceType::Unknown:
+        ASSERT_NOT_REACHED();
+        break;
+    }
+#else
+    UNUSED_PARAM(device);
+    UNUSED_PARAM(constraints);
+#endif
+    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)
 {
 }
@@ -62,7 +99,7 @@ DisplayCaptureSourceCocoa::DisplayCaptureSourceCocoa(String&& name)
 DisplayCaptureSourceCocoa::~DisplayCaptureSourceCocoa()
 {
 #if PLATFORM(IOS_FAMILY)
-    RealtimeMediaSourceCenter::singleton().videoCaptureFactory().unsetActiveSource(*this);
+    RealtimeMediaSourceCenter::singleton().displayCaptureFactory().unsetActiveSource(*this);
 #endif
 }
 
@@ -72,8 +109,8 @@ const RealtimeMediaSourceCapabilities& DisplayCaptureSourceCocoa::capabilities()
         RealtimeMediaSourceCapabilities capabilities(settings().supportedConstraints());
 
         // FIXME: what should these be?
-        capabilities.setWidth(CapabilityValueOrRange(72, 2880));
-        capabilities.setHeight(CapabilityValueOrRange(45, 1800));
+        capabilities.setWidth(CapabilityValueOrRange(1, 3840));
+        capabilities.setHeight(CapabilityValueOrRange(1, 2160));
         capabilities.setFrameRate(CapabilityValueOrRange(.01, 30.0));
 
         m_capabilities = WTFMove(capabilities);
@@ -91,7 +128,7 @@ const RealtimeMediaSourceSettings& DisplayCaptureSourceCocoa::settings()
         settings.setWidth(size.width());
         settings.setHeight(size.height());
 
-        settings.setDisplaySurface(surfaceType());
+        settings.setDisplaySurface(m_capturer->surfaceType());
         settings.setLogicalSurface(false);
 
         RealtimeMediaSourceSupportedConstraints supportedConstraints;
@@ -122,11 +159,14 @@ void DisplayCaptureSourceCocoa::settingsDidChange(OptionSet<RealtimeMediaSourceS
 void DisplayCaptureSourceCocoa::startProducingData()
 {
 #if PLATFORM(IOS_FAMILY)
-    RealtimeMediaSourceCenter::singleton().videoCaptureFactory().setActiveSource(*this);
+    RealtimeMediaSourceCenter::singleton().displayCaptureFactory().setActiveSource(*this);
 #endif
 
     m_startTime = MonotonicTime::now();
     m_timer.startRepeating(1_s / frameRate());
+
+    if (!m_capturer->start(frameRate()))
+        captureFailed();
 }
 
 void DisplayCaptureSourceCocoa::stopProducingData()
@@ -134,6 +174,8 @@ void DisplayCaptureSourceCocoa::stopProducingData()
     m_timer.stop();
     m_elapsedTime += MonotonicTime::now() - m_startTime;
     m_startTime = MonotonicTime::nan();
+
+    m_capturer->stop();
 }
 
 Seconds DisplayCaptureSourceCocoa::elapsedTime()
@@ -144,13 +186,32 @@ Seconds DisplayCaptureSourceCocoa::elapsedTime()
     return m_elapsedTime + (MonotonicTime::now() - m_startTime);
 }
 
-IntSize DisplayCaptureSourceCocoa::frameSize() const
+// We keep the aspect ratio of the intrinsic size for the frame size as getDisplayMedia allows max constraints only.
+void DisplayCaptureSourceCocoa::updateFrameSize()
 {
-    IntSize frameSize = size();
-    if (frameSize.isEmpty())
-        return intrinsicSize();
+    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());
 
-    return frameSize;
+    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()
@@ -164,7 +225,7 @@ void DisplayCaptureSourceCocoa::emitFrame()
 
     auto sampleTime = MediaTime::createWithDouble((elapsedTime() + 100_ms).seconds());
 
-    auto frame = generateFrame();
+    auto frame = m_capturer->generateFrame();
     auto imageSize = WTF::switchOn(frame,
         [](RetainPtr<IOSurfaceRef> surface) -> IntSize {
             if (!surface)
@@ -184,22 +245,23 @@ void DisplayCaptureSourceCocoa::emitFrame()
     if (imageSize.isEmpty())
         return;
 
-    setIntrinsicSize(imageSize);
-
-    auto mediaSampleSize = frameSize();
+    if (intrinsicSize() != imageSize) {
+        setIntrinsicSize(imageSize);
+        updateFrameSize();
+    }
 
-    RefPtr<MediaSample> sample = WTF::switchOn(frame,
-        [this, sampleTime, mediaSampleSize](RetainPtr<IOSurfaceRef> surface) -> RefPtr<MediaSample> {
+    auto sample = WTF::switchOn(frame,
+        [this, sampleTime](RetainPtr<IOSurfaceRef> surface) -> RefPtr<MediaSample> {
             if (!surface)
                 return nullptr;
 
-            return m_imageTransferSession->createMediaSample(surface.get(), sampleTime, mediaSampleSize);
+            return m_imageTransferSession->createMediaSample(surface.get(), sampleTime, size());
         },
-        [this, sampleTime, mediaSampleSize](RetainPtr<CGImageRef> image) -> RefPtr<MediaSample> {
+        [this, sampleTime](RetainPtr<CGImageRef> image) -> RefPtr<MediaSample> {
             if (!image)
                 return nullptr;
 
-            return m_imageTransferSession->createMediaSample(image.get(), sampleTime, mediaSampleSize);
+            return m_imageTransferSession->createMediaSample(image.get(), sampleTime, size());
         }
     );
 
@@ -212,6 +274,19 @@ void DisplayCaptureSourceCocoa::emitFrame()
 #endif
 }
 
+#if !RELEASE_LOG_DISABLED
+void DisplayCaptureSourceCocoa::Capturer::setLogger(const Logger& newLogger, const void* newLogIdentifier)
+{
+    m_logger = &newLogger;
+    m_logIdentifier = newLogIdentifier;
+}
+
+WTFLogChannel& DisplayCaptureSourceCocoa::Capturer::logChannel() const
+{
+    return LogWebRTC;
+}
+#endif
+
 } // namespace WebCore
 
 #endif // ENABLE(MEDIA_STREAM)
index 186f256..ffc14bc 100644 (file)
@@ -33,6 +33,7 @@
 #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;
@@ -49,36 +50,66 @@ class CaptureDeviceInfo;
 class ImageTransferSessionVT;
 class PixelBufferConformerCV;
 
-class DisplayCaptureSourceCocoa : public RealtimeMediaSource {
+class DisplayCaptureSourceCocoa final : public RealtimeMediaSource {
 public:
-
-protected:
-    DisplayCaptureSourceCocoa(String&& name);
-    virtual ~DisplayCaptureSourceCocoa();
-
     using DisplayFrameType = WTF::Variant<RetainPtr<CGImageRef>, RetainPtr<IOSurfaceRef>>;
-    virtual DisplayFrameType generateFrame() = 0;
-
-    virtual RealtimeMediaSourceSettings::DisplaySurfaceType surfaceType() const = 0;
-
-    void startProducingData() override;
-    void stopProducingData() override;
+    class Capturer
+#if !RELEASE_LOG_DISABLED
+        : public LoggerHelper
+#endif
+    {
+        WTF_MAKE_FAST_ALLOCATED;
+    public:
+        virtual ~Capturer() = default;
+
+        virtual bool start(float frameRate) = 0;
+        virtual void stop() = 0;
+        virtual DisplayFrameType generateFrame() = 0;
+        virtual CaptureDevice::DeviceType deviceType() const = 0;
+        virtual RealtimeMediaSourceSettings::DisplaySurfaceType surfaceType() const = 0;
+        virtual void commitConfiguration(float frameRate) = 0;
+
+#if !RELEASE_LOG_DISABLED
+        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;
+#endif
+
+    private:
+#if !RELEASE_LOG_DISABLED
+        RefPtr<const Logger> m_logger;
+        const void* m_logIdentifier;
+#endif
+    };
+
+    static CaptureSourceOrError create(const CaptureDevice&, const MediaConstraints*);
+    static CaptureSourceOrError create(Expected<UniqueRef<Capturer>, String>&&, const CaptureDevice&, const MediaConstraints*);
 
     Seconds elapsedTime();
-
-    void settingsDidChange(OptionSet<RealtimeMediaSourceSettings::Flag>) override;
-
-    IntSize frameSize() const;
+    void updateFrameSize();
 
 private:
+    DisplayCaptureSourceCocoa(UniqueRef<Capturer>&&, String&& name);
+    ~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 { return m_capturer->commitConfiguration(frameRate()); }
+
+#if !RELEASE_LOG_DISABLED
+    const char* logClassName() const final { return "DisplayCaptureSourceCocoa"; }
+#endif
 
     void emitFrame();
 
+    UniqueRef<Capturer> m_capturer;
     Optional<RealtimeMediaSourceCapabilities> m_capabilities;
     Optional<RealtimeMediaSourceSettings> m_currentSettings;
     RealtimeMediaSourceSupportedConstraints m_supportedConstraints;
index 95a8cf0..81ed997 100644 (file)
@@ -46,7 +46,9 @@ class ImageTransferSessionVT;
 
 class MockRealtimeVideoSourceMac final : public MockRealtimeVideoSource {
 public:
-    virtual ~MockRealtimeVideoSourceMac() = default;
+    static Ref<MockRealtimeVideoSource> createForMockDisplayCapturer(String&& deviceID, String&& name, String&& hashSalt);
+
+    ~MockRealtimeVideoSourceMac() = default;
 
 private:
     friend class MockRealtimeVideoSource;
index d1c016f..b84e0b0 100644 (file)
@@ -71,6 +71,11 @@ CaptureSourceOrError MockRealtimeVideoSource::create(String&& deviceID, String&&
     return CaptureSourceOrError(RealtimeVideoSource::create(WTFMove(source)));
 }
 
+Ref<MockRealtimeVideoSource> MockRealtimeVideoSourceMac::createForMockDisplayCapturer(String&& deviceID, String&& name, String&& hashSalt)
+{
+    return adoptRef(*new MockRealtimeVideoSourceMac(WTFMove(deviceID), WTFMove(name), WTFMove(hashSalt)));
+}
+
 MockRealtimeVideoSourceMac::MockRealtimeVideoSourceMac(String&& deviceID, String&& name, String&& hashSalt)
     : MockRealtimeVideoSource(WTFMove(deviceID), WTFMove(name), WTFMove(hashSalt))
 {
index a6a0dab..0bed589 100644 (file)
@@ -38,8 +38,8 @@
 #include "DisplayCaptureManagerCocoa.h"
 #include "Logging.h"
 #include "MediaStreamPrivate.h"
-#include "ScreenDisplayCaptureSourceMac.h"
-#include "WindowDisplayCaptureSourceMac.h"
+#include "ScreenDisplayCapturerMac.h"
+#include "WindowDisplayCapturerMac.h"
 #include <wtf/MainThread.h>
 
 namespace WebCore {
@@ -72,23 +72,11 @@ public:
         UNUSED_PARAM(device);
         UNUSED_PARAM(constraints);
 #endif
-        switch (device.type()) {
-        case CaptureDevice::DeviceType::Screen:
 #if PLATFORM(MAC)
-            return ScreenDisplayCaptureSourceMac::create(String { device.persistentId() }, constraints);
-#endif
-        case CaptureDevice::DeviceType::Window:
-#if PLATFORM(MAC)
-            return WindowDisplayCaptureSourceMac::create(String { device.persistentId() }, constraints);
-#endif
-        case CaptureDevice::DeviceType::Microphone:
-        case CaptureDevice::DeviceType::Camera:
-        case CaptureDevice::DeviceType::Unknown:
-            ASSERT_NOT_REACHED();
-            break;
-        }
-
+        return DisplayCaptureSourceCocoa::create(device, constraints);
+#else
         return { };
+#endif
     }
 private:
     CaptureDeviceManager& displayCaptureDeviceManager() { return DisplayCaptureManagerCocoa::singleton(); }
@@ -39,36 +39,34 @@ typedef struct opaqueCMSampleBuffer *CMSampleBufferRef;
 
 namespace WebCore {
 
-class ScreenDisplayCaptureSourceMac : public DisplayCaptureSourceCocoa {
+class ScreenDisplayCapturerMac final : public DisplayCaptureSourceCocoa::Capturer, public CanMakeWeakPtr<ScreenDisplayCapturerMac> {
 public:
-    static CaptureSourceOrError create(String&&, const MediaConstraints*);
+    static Expected<UniqueRef<DisplayCaptureSourceCocoa::Capturer>, String> create(const String&);
+
+    explicit ScreenDisplayCapturerMac(uint32_t);
+    ~ScreenDisplayCapturerMac();
 
     static Optional<CaptureDevice> screenCaptureDeviceWithPersistentID(const String&);
     static void screenCaptureDevices(Vector<CaptureDevice>&);
 
 private:
-    ScreenDisplayCaptureSourceMac(uint32_t, String&&);
-    virtual ~ScreenDisplayCaptureSourceMac();
-
     static void displayReconfigurationCallBack(CGDirectDisplayID, CGDisplayChangeSummaryFlags, void*);
 
-    void displayWasReconfigured(CGDirectDisplayID, CGDisplayChangeSummaryFlags);
-
+    // DisplayCaptureSourceCocoa::Capturer
+    bool start(float frameRate) final;
+    void stop() final;
     DisplayCaptureSourceCocoa::DisplayFrameType generateFrame() final;
     RealtimeMediaSourceSettings::DisplaySurfaceType surfaceType() const final { return RealtimeMediaSourceSettings::DisplaySurfaceType::Monitor; }
-
-    void startProducingData() final;
-    void stopProducingData() final;
-    void commitConfiguration() final;
+    void commitConfiguration(float frameRate) final;
     CaptureDevice::DeviceType deviceType() const final { return CaptureDevice::DeviceType::Screen; }
-
-    bool createDisplayStream();
-    void startDisplayStream();
-
 #if !RELEASE_LOG_DISABLED
-    const char* logClassName() const override { return "ScreenDisplayCaptureSourceMac"; }
+    const char* logClassName() const final { return "ScreenDisplayCapturerMac"; }
 #endif
 
+    void displayWasReconfigured(CGDirectDisplayID, CGDisplayChangeSummaryFlags);
+    bool createDisplayStream(float frameRate);
+    bool startDisplayStream(float frameRate);
+
     class DisplaySurface {
     public:
         DisplaySurface() = default;
@@ -23,8 +23,8 @@
  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  */
 
-#import "config.h"
-#import "ScreenDisplayCaptureSourceMac.h"
+#include "config.h"
+#include "ScreenDisplayCapturerMac.h"
 
 #if ENABLE(MEDIA_STREAM) && PLATFORM(MAC)
 
@@ -53,19 +53,19 @@ static Optional<CGDirectDisplayID> updateDisplayID(CGDirectDisplayID displayID)
     uint32_t displayCount = 0;
     auto err = CGGetActiveDisplayList(0, nullptr, &displayCount);
     if (err) {
-        RELEASE_LOG(Media, "CGGetActiveDisplayList() returned error %d when trying to get display count", static_cast<int>(err));
+        RELEASE_LOG(WebRTC, "CGGetActiveDisplayList() returned error %d when trying to get display count", static_cast<int>(err));
         return WTF::nullopt;
     }
 
     if (!displayCount) {
-        RELEASE_LOG(Media, "CGGetActiveDisplayList() returned a display count of 0");
+        RELEASE_LOG(WebRTC, "CGGetActiveDisplayList() returned a display count of 0");
         return WTF::nullopt;
     }
 
     Vector<CGDirectDisplayID> activeDisplays(displayCount);
     err = CGGetActiveDisplayList(displayCount, activeDisplays.data(), &displayCount);
     if (err) {
-        RELEASE_LOG(Media, "CGGetActiveDisplayList() returned error %d when trying to get the active display list", static_cast<int>(err));
+        RELEASE_LOG(WebRTC, "CGGetActiveDisplayList() returned error %d when trying to get the active display list", static_cast<int>(err));
         return WTF::nullopt;
     }
 
@@ -78,33 +78,26 @@ static Optional<CGDirectDisplayID> updateDisplayID(CGDirectDisplayID displayID)
     return WTF::nullopt;
 }
 
-CaptureSourceOrError ScreenDisplayCaptureSourceMac::create(String&& deviceID, const MediaConstraints* constraints)
+Expected<UniqueRef<DisplayCaptureSourceCocoa::Capturer>, String> ScreenDisplayCapturerMac::create(const String& deviceID)
 {
     bool ok;
     auto displayID = deviceID.toUIntStrict(&ok);
-    if (!ok) {
-        RELEASE_LOG(Media, "ScreenDisplayCaptureSourceMac::create: Display ID does not convert to 32-bit integer");
-        return { };
-    }
+    if (!ok)
+        return makeUnexpected("Invalid display device ID"_s);
 
     auto actualDisplayID = updateDisplayID(displayID);
     if (!actualDisplayID)
-        return { };
-
-    auto source = adoptRef(*new ScreenDisplayCaptureSourceMac(actualDisplayID.value(), "Screen"_s)); // FIXME: figure out what title to use
-    if (constraints && source->applyConstraints(*constraints))
-        return { };
+        return makeUnexpected("Invalid display ID"_s);
 
-    return CaptureSourceOrError(WTFMove(source));
+    return UniqueRef<DisplayCaptureSourceCocoa::Capturer>(makeUniqueRef<ScreenDisplayCapturerMac>(actualDisplayID.value()));
 }
 
-ScreenDisplayCaptureSourceMac::ScreenDisplayCaptureSourceMac(uint32_t displayID, String&& title)
-    : DisplayCaptureSourceCocoa(WTFMove(title))
-    , m_displayID(displayID)
+ScreenDisplayCapturerMac::ScreenDisplayCapturerMac(uint32_t displayID)
+    : m_displayID(displayID)
 {
 }
 
-ScreenDisplayCaptureSourceMac::~ScreenDisplayCaptureSourceMac()
+ScreenDisplayCapturerMac::~ScreenDisplayCapturerMac()
 {
     if (m_observingDisplayChanges)
         CGDisplayRemoveReconfigurationCallback(displayReconfigurationCallBack, this);
@@ -112,7 +105,7 @@ ScreenDisplayCaptureSourceMac::~ScreenDisplayCaptureSourceMac()
     m_currentFrame = nullptr;
 }
 
-bool ScreenDisplayCaptureSourceMac::createDisplayStream()
+bool ScreenDisplayCapturerMac::createDisplayStream(float frameRate)
 {
     static const int screenQueueMaximumLength = 6;
 
@@ -121,7 +114,6 @@ bool ScreenDisplayCaptureSourceMac::createDisplayStream()
     auto actualDisplayID = updateDisplayID(m_displayID);
     if (!actualDisplayID) {
         ERROR_LOG_IF(loggerPtr(), LOGIDENTIFIER, "invalid display ID: ", m_displayID);
-        captureFailed();
         return false;
     }
 
@@ -137,16 +129,14 @@ bool ScreenDisplayCaptureSourceMac::createDisplayStream()
         auto screenHeight = CGDisplayModeGetPixelsHigh(displayMode.get());
         if (!screenWidth || !screenHeight) {
             ERROR_LOG_IF(loggerPtr(), LOGIDENTIFIER, "unable to get screen width/height");
-            captureFailed();
             return false;
         }
-        setIntrinsicSize(IntSize(screenWidth, screenHeight));
 
         if (!m_captureQueue)
-            m_captureQueue = adoptOSObject(dispatch_queue_create("ScreenDisplayCaptureSourceMac Capture Queue", DISPATCH_QUEUE_SERIAL));
+            m_captureQueue = adoptOSObject(dispatch_queue_create("ScreenDisplayCapturerMac Capture Queue", DISPATCH_QUEUE_SERIAL));
 
         NSDictionary* streamOptions = @{
-            (__bridge NSString *)kCGDisplayStreamMinimumFrameTime : @(1 / frameRate()),
+            (__bridge NSString *)kCGDisplayStreamMinimumFrameTime : @(1 / frameRate),
             (__bridge NSString *)kCGDisplayStreamQueueDepth : @(screenQueueMaximumLength),
             (__bridge NSString *)kCGDisplayStreamColorSpace : (__bridge id)sRGBColorSpaceRef(),
             (__bridge NSString *)kCGDisplayStreamShowCursor : @YES,
@@ -173,7 +163,6 @@ bool ScreenDisplayCaptureSourceMac::createDisplayStream()
         m_displayStream = adoptCF(CGDisplayStreamCreateWithDispatchQueue(m_displayID, screenWidth, screenHeight, preferedPixelBufferFormat(), (__bridge CFDictionaryRef)streamOptions, m_captureQueue.get(), frameAvailableBlock));
         if (!m_displayStream) {
             ERROR_LOG_IF(loggerPtr(), LOGIDENTIFIER, "CGDisplayStreamCreate failed");
-            captureFailed();
             return false;
         }
     }
@@ -186,21 +175,19 @@ bool ScreenDisplayCaptureSourceMac::createDisplayStream()
     return true;
 }
 
-void ScreenDisplayCaptureSourceMac::startProducingData()
+bool ScreenDisplayCapturerMac::start(float frameRate)
 {
     ALWAYS_LOG_IF(loggerPtr(), LOGIDENTIFIER);
-    DisplayCaptureSourceCocoa::startProducingData();
 
     if (m_isRunning)
-        return;
+        return true;
 
-    startDisplayStream();
+    return startDisplayStream(frameRate);
 }
 
-void ScreenDisplayCaptureSourceMac::stopProducingData()
+void ScreenDisplayCapturerMac::stop()
 {
     ALWAYS_LOG_IF(loggerPtr(), LOGIDENTIFIER);
-    DisplayCaptureSourceCocoa::stopProducingData();
 
     if (!m_isRunning)
         return;
@@ -211,53 +198,53 @@ void ScreenDisplayCaptureSourceMac::stopProducingData()
     m_isRunning = false;
 }
 
-DisplayCaptureSourceCocoa::DisplayFrameType ScreenDisplayCaptureSourceMac::generateFrame()
+DisplayCaptureSourceCocoa::DisplayFrameType ScreenDisplayCapturerMac::generateFrame()
 {
     return DisplayCaptureSourceCocoa::DisplayFrameType { RetainPtr<IOSurfaceRef> { m_currentFrame.ioSurface() } };
 }
 
-void ScreenDisplayCaptureSourceMac::startDisplayStream()
+bool ScreenDisplayCapturerMac::startDisplayStream(float frameRate)
 {
     auto actualDisplayID = updateDisplayID(m_displayID);
     if (!actualDisplayID)
-        return;
+        return false;
 
     if (m_displayID != actualDisplayID.value()) {
         m_displayID = actualDisplayID.value();
         ALWAYS_LOG_IF(loggerPtr(), LOGIDENTIFIER, "display ID changed to ", static_cast<int>(m_displayID));
     }
 
-    if (!m_displayStream && !createDisplayStream())
-        return;
+    if (!m_displayStream && !createDisplayStream(frameRate))
+        return false;
 
     auto err = CGDisplayStreamStart(m_displayStream.get());
     if (err) {
         ERROR_LOG_IF(loggerPtr(), LOGIDENTIFIER, "CGDisplayStreamStart failed with error ", static_cast<int>(err));
-        captureFailed();
-        return;
+        return false;
     }
 
     m_isRunning = true;
+    return true;
 }
 
-void ScreenDisplayCaptureSourceMac::commitConfiguration()
+void ScreenDisplayCapturerMac::commitConfiguration(float frameRate)
 {
     if (m_isRunning && !m_displayStream)
-        startDisplayStream();
+        startDisplayStream(frameRate);
 }
 
-void ScreenDisplayCaptureSourceMac::displayWasReconfigured(CGDirectDisplayID, CGDisplayChangeSummaryFlags)
+void ScreenDisplayCapturerMac::displayWasReconfigured(CGDirectDisplayID, CGDisplayChangeSummaryFlags)
 {
     // FIXME: implement!
 }
 
-void ScreenDisplayCaptureSourceMac::displayReconfigurationCallBack(CGDirectDisplayID display, CGDisplayChangeSummaryFlags flags, void *userInfo)
+void ScreenDisplayCapturerMac::displayReconfigurationCallBack(CGDirectDisplayID display, CGDisplayChangeSummaryFlags flags, void *userInfo)
 {
     if (userInfo)
-        reinterpret_cast<ScreenDisplayCaptureSourceMac *>(userInfo)->displayWasReconfigured(display, flags);
+        reinterpret_cast<ScreenDisplayCapturerMac *>(userInfo)->displayWasReconfigured(display, flags);
 }
 
-void ScreenDisplayCaptureSourceMac::newFrame(CGDisplayStreamFrameStatus status, DisplaySurface&& newFrame)
+void ScreenDisplayCapturerMac::newFrame(CGDisplayStreamFrameStatus status, DisplaySurface&& newFrame)
 {
     switch (status) {
     case kCGDisplayStreamFrameStatusFrameComplete:
@@ -267,23 +254,23 @@ void ScreenDisplayCaptureSourceMac::newFrame(CGDisplayStreamFrameStatus status,
         break;
 
     case kCGDisplayStreamFrameStatusFrameBlank:
-        RELEASE_LOG(Media, "ScreenDisplayCaptureSourceMac::frameAvailable: kCGDisplayStreamFrameStatusFrameBlank");
+        RELEASE_LOG(WebRTC, "ScreenDisplayCapturerMac::frameAvailable: kCGDisplayStreamFrameStatusFrameBlank");
         break;
 
     case kCGDisplayStreamFrameStatusStopped:
-        RELEASE_LOG(Media, "ScreenDisplayCaptureSourceMac::frameAvailable: kCGDisplayStreamFrameStatusStopped");
+        RELEASE_LOG(WebRTC, "ScreenDisplayCapturerMac::frameAvailable: kCGDisplayStreamFrameStatusStopped");
         break;
     }
 
     m_currentFrame = WTFMove(newFrame);
 }
 
-Optional<CaptureDevice> ScreenDisplayCaptureSourceMac::screenCaptureDeviceWithPersistentID(const String& deviceID)
+Optional<CaptureDevice> ScreenDisplayCapturerMac::screenCaptureDeviceWithPersistentID(const String& deviceID)
 {
     bool ok;
     auto displayID = deviceID.toUIntStrict(&ok);
     if (!ok) {
-        RELEASE_LOG(Media, "ScreenDisplayCaptureSourceMac::screenCaptureDeviceWithPersistentID: display ID does not convert to 32-bit integer");
+        RELEASE_LOG(WebRTC, "ScreenDisplayCapturerMac::screenCaptureDeviceWithPersistentID: display ID does not convert to 32-bit integer");
         return WTF::nullopt;
     }
 
@@ -297,7 +284,7 @@ Optional<CaptureDevice> ScreenDisplayCaptureSourceMac::screenCaptureDeviceWithPe
     return device;
 }
 
-void ScreenDisplayCaptureSourceMac::screenCaptureDevices(Vector<CaptureDevice>& displays)
+void ScreenDisplayCapturerMac::screenCaptureDevices(Vector<CaptureDevice>& displays)
 {
     auto screenID = displayID([NSScreen mainScreen]);
     if (CGDisplayIDToOpenGLDisplayMask(screenID)) {
@@ -310,19 +297,19 @@ void ScreenDisplayCaptureSourceMac::screenCaptureDevices(Vector<CaptureDevice>&
     uint32_t displayCount = 0;
     auto err = CGGetActiveDisplayList(0, nullptr, &displayCount);
     if (err) {
-        RELEASE_LOG(Media, "CGGetActiveDisplayList() returned error %d when trying to get display count", (int)err);
+        RELEASE_LOG(WebRTC, "CGGetActiveDisplayList() returned error %d when trying to get display count", (int)err);
         return;
     }
 
     if (!displayCount) {
-        RELEASE_LOG(Media, "CGGetActiveDisplayList() returned a display count of 0");
+        RELEASE_LOG(WebRTC, "CGGetActiveDisplayList() returned a display count of 0");
         return;
     }
 
     Vector<CGDirectDisplayID> activeDisplays(displayCount);
     err = CGGetActiveDisplayList(displayCount, activeDisplays.data(), &displayCount);
     if (err) {
-        RELEASE_LOG(Media, "CGGetActiveDisplayList() returned error %d when trying to get the active display list", (int)err);
+        RELEASE_LOG(WebRTC, "CGGetActiveDisplayList() returned error %d when trying to get the active display list", (int)err);
         return;
     }
 
@@ -38,20 +38,27 @@ namespace WebCore {
 
 class PixelBufferConformerCV;
 
-class WindowDisplayCaptureSourceMac : public DisplayCaptureSourceCocoa {
+class WindowDisplayCapturerMac final : public DisplayCaptureSourceCocoa::Capturer {
 public:
-    static CaptureSourceOrError create(String&&, const MediaConstraints*);
+    static Expected<UniqueRef<DisplayCaptureSourceCocoa::Capturer>, String> create(const String&);
+
+    explicit WindowDisplayCapturerMac(uint32_t);
+    virtual ~WindowDisplayCapturerMac() = default;
 
     static Optional<CaptureDevice> windowCaptureDeviceWithPersistentID(const String&);
     static void windowCaptureDevices(Vector<CaptureDevice>&);
 
 private:
-    WindowDisplayCaptureSourceMac(uint32_t, String&&);
-    virtual ~WindowDisplayCaptureSourceMac() = default;
-
+    // DisplayCaptureSourceCocoa::Capturer
+    bool start(float) final { return true; }
+    void stop() final { }
     DisplayCaptureSourceCocoa::DisplayFrameType generateFrame() final;
     RealtimeMediaSourceSettings::DisplaySurfaceType surfaceType() const final { return RealtimeMediaSourceSettings::DisplaySurfaceType::Window; }
     CaptureDevice::DeviceType deviceType() const final { return CaptureDevice::DeviceType::Window; }
+    void commitConfiguration(float) final { }
+#if !RELEASE_LOG_DISABLED
+    const char* logClassName() const final { return "WindowDisplayCapturerMac"; }
+#endif
 
     RetainPtr<CGImageRef> windowImage();
 
@@ -24,7 +24,7 @@
  */
 
 #import "config.h"
-#import "WindowDisplayCaptureSourceMac.h"
+#import "WindowDisplayCapturerMac.h"
 
 #if ENABLE(MEDIA_STREAM) && PLATFORM(MAC)
 
 #import "PixelBufferConformerCV.h"
 #import "PlatformLayer.h"
 #import "RealtimeMediaSourceSettings.h"
-#import <pal/cf/CoreMediaSoftLink.h>
 #import <pal/spi/cg/CoreGraphicsSPI.h>
 #import <wtf/cf/TypeCastsCF.h>
 
+#import <pal/cf/CoreMediaSoftLink.h>
 #import "CoreVideoSoftLink.h"
 
 WTF_DECLARE_CF_TYPE_TRAIT(CGImage);
@@ -52,7 +52,7 @@ static bool anyOfCGWindow(const Function<bool(CFDictionaryRef info, unsigned id,
 {
     auto windows = adoptCF(CGWindowListCopyWindowInfo(kCGWindowListOptionOnScreenOnly | kCGWindowListExcludeDesktopElements, kCGNullWindowID));
     if (!windows) {
-        RELEASE_LOG(Media, "CGWindowListCopyWindowInfo returned NULL");
+        RELEASE_LOG(WebRTC, "CGWindowListCopyWindowInfo returned NULL");
         return false;
     }
 
@@ -102,54 +102,45 @@ static RetainPtr<CFDictionaryRef> windowDescription(CGWindowID id)
     return checked_cf_cast<CFDictionaryRef>(CFArrayGetValueAtIndex(windows.get(), 0));
 }
 
-CaptureSourceOrError WindowDisplayCaptureSourceMac::create(String&& windowID, const MediaConstraints* constraints)
+Expected<UniqueRef<DisplayCaptureSourceCocoa::Capturer>, String> WindowDisplayCapturerMac::create(const String& deviceID)
 {
     bool ok;
-    auto actualID = windowID.toUIntStrict(&ok);
-    if (!ok) {
-        RELEASE_LOG(Media, "WindowDisplayCaptureSourceMac::create: window ID does not convert to 32-bit integer");
-        return { };
-    }
-
-    auto windowInfo = windowDescription(actualID);
-    if (!windowInfo) {
-        RELEASE_LOG(Media, "WindowDisplayCaptureSourceMac::create: invalid window ID");
-        return { };
-    }
+    auto displayID = deviceID.toUIntStrict(&ok);
+    if (!ok)
+        return makeUnexpected("Invalid window device ID"_s);
 
-    auto source = adoptRef(*new WindowDisplayCaptureSourceMac(actualID, checked_cf_cast<CFStringRef>(CFDictionaryGetValue(windowInfo.get(), kCGWindowName))));
-    if (constraints && source->applyConstraints(*constraints))
-        return { };
+    auto windowInfo = windowDescription(displayID);
+    if (!windowInfo)
+        return makeUnexpected("Invalid window ID"_s);
 
-    return CaptureSourceOrError(WTFMove(source));
+    return UniqueRef<DisplayCaptureSourceCocoa::Capturer>(makeUniqueRef<WindowDisplayCapturerMac>(displayID));
 }
 
-WindowDisplayCaptureSourceMac::WindowDisplayCaptureSourceMac(uint32_t windowID, String&& title)
-    : DisplayCaptureSourceCocoa(WTFMove(title))
-    , m_windowID(windowID)
+WindowDisplayCapturerMac::WindowDisplayCapturerMac(uint32_t windowID)
+    : m_windowID(windowID)
 {
 }
 
-RetainPtr<CGImageRef> WindowDisplayCaptureSourceMac::windowImage()
+RetainPtr<CGImageRef> WindowDisplayCapturerMac::windowImage()
 {
     auto image = adoptCF(CGWindowListCreateImage(CGRectNull, kCGWindowListOptionIncludingWindow, m_windowID, kCGWindowImageBoundsIgnoreFraming | kCGWindowImageShouldBeOpaque));
     if (!image)
-        RELEASE_LOG(Media, "WindowDisplayCaptureSourceMac::windowImage: failed to capture window image");
+        RELEASE_LOG(WebRTC, "WindowDisplayCapturerMac::windowImage: failed to capture window image");
 
     return image;
 }
 
-DisplayCaptureSourceCocoa::DisplayFrameType WindowDisplayCaptureSourceMac::generateFrame()
+DisplayCaptureSourceCocoa::DisplayFrameType WindowDisplayCapturerMac::generateFrame()
 {
     return DisplayCaptureSourceCocoa::DisplayFrameType { RetainPtr<CGImageRef> { windowImage() } };
 }
 
-Optional<CaptureDevice> WindowDisplayCaptureSourceMac::windowCaptureDeviceWithPersistentID(const String& idString)
+Optional<CaptureDevice> WindowDisplayCapturerMac::windowCaptureDeviceWithPersistentID(const String& idString)
 {
     bool ok;
     auto windowID = idString.toUIntStrict(&ok);
     if (!ok) {
-        RELEASE_LOG(Media, "WindowDisplayCaptureSourceMac::windowCaptureDeviceWithPersistentID: window ID does not convert to 32-bit integer");
+        RELEASE_LOG(WebRTC, "WindowDisplayCapturerMac::windowCaptureDeviceWithPersistentID: window ID does not convert to 32-bit integer");
         return WTF::nullopt;
     }
 
@@ -162,7 +153,7 @@ Optional<CaptureDevice> WindowDisplayCaptureSourceMac::windowCaptureDeviceWithPe
         return true;
 
     })) {
-        RELEASE_LOG(Media, "WindowDisplayCaptureSourceMac::windowCaptureDeviceWithPersistentID: window ID is not valid");
+        RELEASE_LOG(WebRTC, "WindowDisplayCapturerMac::windowCaptureDeviceWithPersistentID: window ID is not valid");
         return WTF::nullopt;
     }
 
@@ -172,7 +163,7 @@ Optional<CaptureDevice> WindowDisplayCaptureSourceMac::windowCaptureDeviceWithPe
     return device;
 }
 
-void WindowDisplayCaptureSourceMac::windowCaptureDevices(Vector<CaptureDevice>& windows)
+void WindowDisplayCapturerMac::windowCaptureDevices(Vector<CaptureDevice>& windows)
 {
     anyOfCGWindow([&] (CFDictionaryRef, int id, const String& title) mutable {
         CaptureDevice device(String::number(id), CaptureDevice::DeviceType::Window, title);
index 2aef513..fc42f6b 100644 (file)
@@ -43,6 +43,8 @@
 
 #if PLATFORM(COCOA)
 #include "CoreAudioCaptureSource.h"
+#include "DisplayCaptureSourceCocoa.h"
+#include "MockRealtimeVideoSourceMac.h"
 #endif
 
 namespace WebCore {
@@ -110,17 +112,59 @@ private:
     CaptureDeviceManager& videoCaptureDeviceManager() final { return MockRealtimeMediaSourceCenter::singleton().videoCaptureDeviceManager(); }
 };
 
+#if PLATFORM(MAC)
+class MockDisplayCapturer final : public DisplayCaptureSourceCocoa::Capturer {
+public:
+    explicit MockDisplayCapturer(const CaptureDevice&);
+
+private:
+    bool start(float) final;
+    void stop() final  { m_source->stop(); }
+    DisplayCaptureSourceCocoa::DisplayFrameType generateFrame() final;
+    RealtimeMediaSourceSettings::DisplaySurfaceType surfaceType() const final { return RealtimeMediaSourceSettings::DisplaySurfaceType::Monitor; }
+    void commitConfiguration(float) final { }
+    CaptureDevice::DeviceType deviceType() const final { return CaptureDevice::DeviceType::Screen; }
+#if !RELEASE_LOG_DISABLED
+    const char* logClassName() const final { return "MockDisplayCapturer"; }
+#endif
+    
+    Ref<MockRealtimeVideoSource> m_source;
+};
+
+MockDisplayCapturer::MockDisplayCapturer(const CaptureDevice& device)
+    : m_source(MockRealtimeVideoSourceMac::createForMockDisplayCapturer(String { device.persistentId() }, String { device.label() }, String { }))
+{
+}
+
+bool MockDisplayCapturer::start(float)
+{
+    m_source->start();
+    return true;
+}
+
+DisplayCaptureSourceCocoa::DisplayFrameType MockDisplayCapturer::generateFrame()
+{
+    if (auto* imageBuffer = m_source->imageBuffer())
+        return imageBuffer->copyNativeImage();
+    return { };
+}
+#endif
+
 class MockRealtimeDisplaySourceFactory : public DisplayCaptureFactory {
 public:
     CaptureSourceOrError createDisplayCaptureSource(const CaptureDevice& device, const MediaConstraints* constraints) final
     {
         if (!MockRealtimeMediaSourceCenter::captureDeviceWithPersistentID(device.type(), device.persistentId()))
-            return { "Unable to find mock  display device with given persistentID"_s };
+            return { "Unable to find mock display device with given persistentID"_s };
 
         switch (device.type()) {
         case CaptureDevice::DeviceType::Screen:
         case CaptureDevice::DeviceType::Window:
+#if PLATFORM(MAC)
+            return DisplayCaptureSourceCocoa::create(UniqueRef<DisplayCaptureSourceCocoa::Capturer>(makeUniqueRef<MockDisplayCapturer>(device)), device, constraints);
+#else
             return MockRealtimeVideoSource::create(String { device.persistentId() }, String { device.label() }, String { }, constraints);
+#endif
             break;
         case CaptureDevice::DeviceType::Microphone:
         case CaptureDevice::DeviceType::Camera:
index 9294a43..f790316 100644 (file)
@@ -48,16 +48,16 @@ class GraphicsContext;
 
 class MockRealtimeVideoSource : public RealtimeVideoCaptureSource, private OrientationNotifier::Observer {
 public:
-
     static CaptureSourceOrError create(String&& deviceID, String&& name, String&& hashSalt, const MediaConstraints*);
 
+    ImageBuffer* imageBuffer() const;
+
 protected:
     MockRealtimeVideoSource(String&& deviceID, String&& name, String&& hashSalt);
 
     virtual void updateSampleBuffer() = 0;
 
     void setCurrentFrame(MediaSample&);
-    ImageBuffer* imageBuffer() const;
 
     Seconds elapsedTime();
     void settingsDidChange(OptionSet<RealtimeMediaSourceSettings::Flag>) override;
@@ -125,6 +125,10 @@ private:
 
 } // namespace WebCore
 
+SPECIALIZE_TYPE_TRAITS_BEGIN(WebCore::MockRealtimeVideoSource)
+    static bool isType(const WebCore::RealtimeMediaSource& source) { return source.isCaptureSource() && source.isMockSource() && (source.deviceType() == WebCore::CaptureDevice::DeviceType::Camera || source.deviceType() == WebCore::CaptureDevice::DeviceType::Screen || source.deviceType() == WebCore::CaptureDevice::DeviceType::Window); }
+SPECIALIZE_TYPE_TRAITS_END()
+
 #endif // ENABLE(MEDIA_STREAM)
 
 #endif // MockRealtimeVideoSource_h