Mock video devices should only support discrete sizes
authoreric.carlson@apple.com <eric.carlson@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Thu, 30 Aug 2018 19:03:55 +0000 (19:03 +0000)
committereric.carlson@apple.com <eric.carlson@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Thu, 30 Aug 2018 19:03:55 +0000 (19:03 +0000)
https://bugs.webkit.org/show_bug.cgi?id=189000
<rdar://problem/43766551>

Reviewed by Youenn Fablet.
Source/WebCore:

While many/most video capture devices only support a finite number of discrete width/height
pairs, our mock video capture devices supported arbitrary width and height combinations which
made it difficult to write realistic tests using them. Change the mock devices to support
finite "presets" like those supported by AVFoundation. Create a RealtimeVideoSource base
class with support for these presets, so the same code will eventually be used by the mock
and real capture devices.

No new tests, existing tests updated for these changes.

* Sources.txt: Add RealtimeVideoSource.cpp, remove MockRealtimeMediaSource.cpp.

* WebCore.xcodeproj/project.pbxproj: Ditto.

* platform/mediastream/MediaConstraints.h: Deal with min constraint less than the supported minimum
and max larger than the supported maximum when there is no ideal.

* platform/mediastream/RealtimeMediaSource.cpp:
(WebCore::RealtimeMediaSource::selectSettings): Use supportsSizeAndFrameRate for widths,
heights, and framerates in advanced constraints so a width and height that are supported but
in the same preset are filtered out.
(WebCore::RealtimeMediaSource::setSize): New.
* platform/mediastream/RealtimeMediaSource.h:

* platform/mediastream/RealtimeMediaSourceSettings.h: Remove an unneeded include.

* platform/mediastream/RealtimeVideoSource.cpp: Added.
(WebCore::RealtimeVideoSource::RealtimeVideoSource):
(WebCore::RealtimeVideoSource::~RealtimeVideoSource):
(WebCore::RealtimeVideoSource::startProducingData):
(WebCore::RealtimeVideoSource::setSupportedFrameRates):
(WebCore::RealtimeVideoSource::addSupportedCapabilities const):
(WebCore::RealtimeVideoSource::supportsSizeAndFrameRate):
(WebCore::RealtimeVideoSource::bestSupportedCaptureSizeForWidthAndHeight):
(WebCore::RealtimeVideoSource::applySize):
(WebCore::RealtimeVideoSource::applySizeAndFrameRate):
(WebCore::RealtimeVideoSource::videoSampleAvailable):
(WebCore::RealtimeVideoSource::applyFrameRate):
(WebCore::RealtimeVideoSource::supportsFrameRate):

* platform/mediastream/RealtimeVideoSource.h: Copied from Source/WebCore/platform/mock/MockRealtimeAudioSource.h.
(WebCore::RealtimeVideoSource::setSupportedCaptureSizes):
(WebCore::RealtimeVideoSource::setDefaultSize):
(WebCore::RealtimeVideoSource::observedFrameRate const):

* platform/mediastream/mac/AVMediaCaptureSource.mm:
(WebCore::AVMediaCaptureSource::initializeSettings): Don't set label, it isn't used.

* platform/mediastream/mac/MockRealtimeVideoSourceMac.mm:
(WebCore::MockRealtimeVideoSourceMac::applySize): Call the base class.

* platform/mock/MockMediaDevice.h:
(WebCore::MockCameraProperties::encode const): Add frame rates, sizes, and facing mode.
(WebCore::MockCameraProperties::decode): Ditto.

* platform/mock/MockRealtimeAudioSource.cpp:
(WebCore::MockRealtimeAudioSource::MockRealtimeAudioSource): No more MockRealtimeMediaSource.
(WebCore::MockRealtimeAudioSource::settings const): Clean up.
(WebCore::MockRealtimeAudioSource::capabilities const): Ditto.
(WebCore::MockRealtimeAudioSource::settingsDidChange): Ditto.
(WebCore::MockRealtimeAudioSource::stopProducingData): m_elapsedTime isn't used, delete it.
(WebCore::MockRealtimeAudioSource::updateSettings): Deleted.
(WebCore::MockRealtimeAudioSource::initializeCapabilities): Deleted.
(WebCore::MockRealtimeAudioSource::initializeSupportedConstraints): Deleted.
(WebCore::MockRealtimeAudioSource::elapsedTime): Deleted.
* platform/mock/MockRealtimeAudioSource.h:

* platform/mock/MockRealtimeMediaSourceCenter.cpp: Moved all of the mock device management
code from MockRealtimeMediaSource.cpp here.
(WebCore::defaultDevices):
(WebCore::devices):
(WebCore::deviceMap):
(WebCore::deviceListForDevice):
(WebCore::createCaptureDevice):
(WebCore::MockRealtimeMediaSourceCenter::resetDevices):
(WebCore::MockRealtimeMediaSourceCenter::setDevices):
(WebCore::MockRealtimeMediaSourceCenter::addDevice):
(WebCore::MockRealtimeMediaSourceCenter::removeDevice):
(WebCore::MockRealtimeMediaSourceCenter::mockDeviceWithPersistentID):
(WebCore::MockRealtimeMediaSourceCenter::captureDeviceWithPersistentID):
(WebCore::MockRealtimeMediaSourceCenter::audioDevices):
(WebCore::MockRealtimeMediaSourceCenter::videoDevices):
(WebCore::MockRealtimeMediaSourceCenter::displayDevices):

* platform/mock/MockRealtimeVideoSource.cpp:
(WebCore::MockRealtimeVideoSource::MockRealtimeVideoSource): Use RealtimeVideoSource, no
more MockRealtimeMediaSource.
(WebCore::MockRealtimeVideoSource::capabilities const): Ditto, cleanup.
(WebCore::MockRealtimeVideoSource::settings const): Ditto.
(WebCore::MockRealtimeVideoSource::settingsDidChange): Ditto.
(WebCore::MockRealtimeVideoSource::startCaptureTimer): Ditto.
(WebCore::MockRealtimeVideoSource::startProducingData): Ditto.
(WebCore::MockRealtimeVideoSource::stopProducingData): Ditto.
(WebCore::MockRealtimeVideoSource::elapsedTime): Ditto.
(WebCore::MockRealtimeVideoSource::applySize): Ditto.
(WebCore::MockRealtimeVideoSource::drawText): Render the actual frame rate.
(WebCore::MockRealtimeVideoSource::generateFrame): Use m_fillColor.
(WebCore::MockRealtimeVideoSource::~MockRealtimeVideoSource): Deleted.
(WebCore::MockRealtimeVideoSource::updateSettings): Deleted.
(WebCore::MockRealtimeVideoSource::initializeCapabilities): Deleted.
(WebCore::MockRealtimeVideoSource::initializeSupportedConstraints): Deleted.
(WebCore::MockRealtimeVideoSource::applyFrameRate): Deleted.
* platform/mock/MockRealtimeVideoSource.h:
(WebCore::MockRealtimeVideoSource::updateSampleBuffer): Deleted.

Source/WebKit:

* UIProcess/WebProcessPool.cpp:
(WebKit::WebProcessPool::resetMockMediaDevices):
* WebProcess/WebProcess.cpp:
(WebKit::WebProcess::resetMockMediaDevices):

LayoutTests:

Updated tests and results now that we have better support for width and height constraints.

* fast/mediastream/MediaDevices-getUserMedia.html:
* fast/mediastream/MediaStreamTrack-getCapabilities-expected.txt:
* fast/mediastream/apply-constraints-advanced-expected.txt:
* fast/mediastream/apply-constraints-advanced.html:
* fast/mediastream/apply-constraints-video-expected.txt:
* fast/mediastream/apply-constraints-video.html:
* fast/mediastream/getUserMedia-default-expected.txt:
* fast/mediastream/getUserMedia-default.html:
* imported/w3c/web-platform-tests/mediacapture-streams/MediaStreamTrack-getSettings.https-expected.txt:
* webrtc/video-interruption.html:
* webrtc/video.html:

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

37 files changed:
LayoutTests/ChangeLog
LayoutTests/fast/mediastream/MediaDevices-getUserMedia.html
LayoutTests/fast/mediastream/MediaStreamTrack-getCapabilities-expected.txt
LayoutTests/fast/mediastream/apply-constraints-advanced-expected.txt
LayoutTests/fast/mediastream/apply-constraints-advanced.html
LayoutTests/fast/mediastream/apply-constraints-video-expected.txt
LayoutTests/fast/mediastream/apply-constraints-video.html
LayoutTests/fast/mediastream/getUserMedia-default-expected.txt
LayoutTests/fast/mediastream/getUserMedia-default.html
LayoutTests/imported/w3c/web-platform-tests/mediacapture-streams/MediaStreamTrack-getSettings.https-expected.txt
LayoutTests/webrtc/video-interruption.html
LayoutTests/webrtc/video.html
Source/WebCore/ChangeLog
Source/WebCore/Sources.txt
Source/WebCore/WebCore.xcodeproj/project.pbxproj
Source/WebCore/platform/mediastream/MediaConstraints.h
Source/WebCore/platform/mediastream/RealtimeMediaSource.cpp
Source/WebCore/platform/mediastream/RealtimeMediaSource.h
Source/WebCore/platform/mediastream/RealtimeVideoSource.cpp [new file with mode: 0644]
Source/WebCore/platform/mediastream/RealtimeVideoSource.h [new file with mode: 0644]
Source/WebCore/platform/mediastream/gstreamer/MockGStreamerVideoCaptureSource.h
Source/WebCore/platform/mediastream/mac/AVMediaCaptureSource.mm
Source/WebCore/platform/mediastream/mac/MockRealtimeAudioSourceMac.mm
Source/WebCore/platform/mediastream/mac/MockRealtimeVideoSourceMac.h
Source/WebCore/platform/mediastream/mac/MockRealtimeVideoSourceMac.mm
Source/WebCore/platform/mock/MockMediaDevice.h
Source/WebCore/platform/mock/MockRealtimeAudioSource.cpp
Source/WebCore/platform/mock/MockRealtimeAudioSource.h
Source/WebCore/platform/mock/MockRealtimeMediaSource.cpp [deleted file]
Source/WebCore/platform/mock/MockRealtimeMediaSource.h [deleted file]
Source/WebCore/platform/mock/MockRealtimeMediaSourceCenter.cpp
Source/WebCore/platform/mock/MockRealtimeMediaSourceCenter.h
Source/WebCore/platform/mock/MockRealtimeVideoSource.cpp
Source/WebCore/platform/mock/MockRealtimeVideoSource.h
Source/WebKit/ChangeLog
Source/WebKit/UIProcess/WebProcessPool.cpp
Source/WebKit/WebProcess/WebProcess.cpp

index 6553ed1..5aedfbd 100644 (file)
@@ -1,3 +1,25 @@
+2018-08-30  Eric Carlson  <eric.carlson@apple.com>
+
+        Mock video devices should only support discrete sizes
+        https://bugs.webkit.org/show_bug.cgi?id=189000
+        <rdar://problem/43766551>
+
+        Reviewed by Youenn Fablet.
+
+        Updated tests and results now that we have better support for width and height constraints.
+
+        * fast/mediastream/MediaDevices-getUserMedia.html:
+        * fast/mediastream/MediaStreamTrack-getCapabilities-expected.txt:
+        * fast/mediastream/apply-constraints-advanced-expected.txt:
+        * fast/mediastream/apply-constraints-advanced.html:
+        * fast/mediastream/apply-constraints-video-expected.txt:
+        * fast/mediastream/apply-constraints-video.html:
+        * fast/mediastream/getUserMedia-default-expected.txt:
+        * fast/mediastream/getUserMedia-default.html:
+        * imported/w3c/web-platform-tests/mediacapture-streams/MediaStreamTrack-getSettings.https-expected.txt:
+        * webrtc/video-interruption.html:
+        * webrtc/video.html:
+
 2018-08-30  Youenn Fablet  <youenn@apple.com>
 
         fast/mediastream/RTCPeerConnection-overloaded-operations.html is flaky after r235484
index 591a7d6..3c934d5 100644 (file)
 
                 videoConstraints = {
                     width: {
-                        min: 400,
-                        exact: 400,
-                        max: 400,
+                        min: 160,
+                        max: 960,
                         ideal: 320
                     },
                     height: 240,
index 41da2be..431f1f0 100644 (file)
@@ -4,12 +4,12 @@ On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE
 
 
 video track capabilities:
-  capabilities.aspectRatio = { max: 1.778, min: 1.333 }
+  capabilities.aspectRatio = { max: 1.778, min: 1.222 }
   capabilities.deviceId = <UUID>
   capabilities.facingMode = [ user ]
-  capabilities.frameRate = { max: 60, min: 15 }
-  capabilities.height = { max: 1080, min: 240 }
-  capabilities.width = { max: 1920, min: 320 }
+  capabilities.frameRate = { max: 30, min: 5 }
+  capabilities.height = { max: 2160, min: 240 }
+  capabilities.width = { max: 3840, min: 320 }
 
 audio track capabilities:
   capabilities.deviceId = <UUID>
index d509a55..75d0bdc 100644 (file)
@@ -12,19 +12,19 @@ PASS video.audioTracks.length is 0
 PASS settings['width'] is 640
 PASS settings['height'] is 480
 
-** Constraint: {"width":{"min":320},"height":{"min":240},"advanced":[{"width":1920,"height":1280}]} - advanced width and height are too big, minimums are less than current, nothing is changed.
+** Constraint: {"width":{"min":320},"height":{"min":240},"advanced":[{"width":1920,"height":1280}]} - advanced width and height are not supported, minimums are less than current, nothing is changed.
 PASS settings['width'] is 640
 PASS settings['height'] is 480
 
-** Constraint: {"width":{"min":640},"height":{"min":480},"advanced":[{"width":1920,"height":1280},{"width":960,"height":720}]} - first width and height in advanced are too big, second is used.
-PASS settings['width'] is 960
-PASS settings['height'] is 720
+** Constraint: {"width":{"min":640},"height":{"min":480},"advanced":[{"width":6000,"height":6000},{"width":1920,"height":1080}]} - first width and height in advanced are too big, second is used.
+PASS settings['width'] is 1920
+PASS settings['height'] is 1080
 
 ** Constraint: {"width":320,"height":240} - reset width and height.
 PASS settings['width'] is 320
 PASS settings['height'] is 240
 
-** Constraint: {"width":{"min":640},"height":{"min":480},"advanced":[{"width":1920,"height":1280}]} - advanced width and height are too big, fall back to required minimums.
+** Constraint: {"width":{"min":640},"height":{"min":480},"advanced":[{"width":7680,"height":4320}]} - advanced width and height are too big, fall back to required minimums.
 PASS settings['width'] is 640
 PASS settings['height'] is 480
 
@@ -32,16 +32,9 @@ PASS settings['height'] is 480
 PASS settings['width'] is 320
 PASS settings['height'] is 240
 
-** Constraint: {"width":{"min":640},"height":{"min":480},"advanced":[{"width":1920,"height":1280},{"aspectRatio":1.777777}]} - advanced width and height are too big, aspectRatio is used.
-PASS settings['width'] is 640
-PASS settings['height'] is 360
-
 ** Constraint: {"advanced":[{"facingMode":"left"},{"facingMode":"right"},{"facingMode":"environment"},{"facingMode":"user"}]} - no required constraints, advanced constraints are ignored.
 PASS settings['facingMode'] is "user"
 
-** Constraint: {"width":{"min":640},"advanced":[{"facingMode":"left"},{"facingMode":"right"},{"facingMode":"user"}]} - first two advanced facingModes are not supported, third is used.
-PASS settings['facingMode'] is "user"
-
 PASS successfullyParsed is true
 
 TEST COMPLETE
index ca65117..922e135 100644 (file)
@@ -12,7 +12,7 @@
                     expected: { width: 640, height: 480 }, 
                 },
                 {
-                    message: "advanced width and height are too big, minimums are less than current, nothing is changed.",
+                    message: "advanced width and height are not supported, minimums are less than current, nothing is changed.",
                     constraint: {
                                     width: { min: 320 },
                                     height: { min: 240 },
                                     width: { min: 640 },
                                     height: { min: 480 },
                                     advanced: [
-                                        { width: 1920, height: 1280 },
-                                        { width: 960, height: 720 },
+                                        { width: 6000, height: 6000 },
+                                        { width: 1920, height: 1080 },
                                     ]
                                  },
-                    expected: { width: 960, height: 720 }, 
+                    expected: { width: 1920, height: 1080 }, 
                 },
                 {
                     message: "reset width and height.",
@@ -45,7 +45,7 @@
                                     width: { min: 640 },
                                     height: {  min: 480 },
                                     advanced: [
-                                        { width: 1920, height: 1280 },
+                                        { width: 7680, height: 4320 },
                                     ]
                                 },
                     expected: { width: 640, height: 480 }, 
                     expected: { width: 320, height: 240 }, 
                 },
                 {
-                    message: "advanced width and height are too big, aspectRatio is used.",
-                    constraint: {
-                                    width: { min: 640 },
-                                    height: { min: 480 },
-                                    advanced: [
-                                        { width: 1920, height: 1280 },
-                                        { aspectRatio: 1.777777 }
-                                    ]
-                                },
-                    expected: { width: 640, height: 360 }, 
-                },
-                {
                     message: "no required constraints, advanced constraints are ignored.",
                     constraint: {
                                     advanced: [
                                 },
                     expected: { facingMode: "user" }, 
                 },
-                {
-                    message: "first two advanced facingModes are not supported, third is used.",
-                    constraint: {
-                                    width: { min: 640 },
-                                    advanced: [
-                                        { facingMode: "left" },
-                                        { facingMode: "right" },
-                                        { facingMode: "user" },
-                                    ]
-                                },
-                    expected: { facingMode: "user" }, 
-                },
             ];
 
             let tester = new ConstraintsTest({ video: true }, tests, "Tests applyConstraints on a video stream track.")
index 3aa71af..d890d36 100644 (file)
@@ -37,56 +37,40 @@ PASS Promise was rejected
 PASS error.constraint is "frameRate"
 PASS settings['frameRate'] is 30
 
-** Constraint: {"width":{"exact":400}} - the 'exact' constraint can be satisfied.
-PASS settings['width'] is 400
-PASS settings['height'] is 240
+** Constraint: {"width":{"exact":960}} - the 'exact' constraint can be satisfied.
+PASS settings['width'] is 960
+PASS settings['height'] is 540
 
-** Constraint: {"width":{"min":300,"ideal":5000}} - the 'ideal' constraint can't be satisfied but the 'min' can, max should be chosen.
-PASS settings['width'] is 1920
-PASS settings['height'] is 240
+** Constraint: {"width":{"min":300,"ideal":5000}} - the 'ideal' constraint can't be satisfied but the 'min' can, maximum value should be chosen.
+PASS settings['width'] is 3840
+PASS settings['height'] is 2160
 
 ** Constraint: {"width":{"min":320,"ideal":1280},"height":{"min":480,"ideal":720}} - 'ideal' and 'min' constraints can be satisfied, 'ideal' should be chosen.
 PASS settings['width'] is 1280
 PASS settings['height'] is 720
 
-** Constraint: {"width":3000} - ideal width is greater than track capability, should be clamped to the maximum value.
-PASS settings['width'] is 1920
+** Constraint: {"width":5000} - ideal width is greater than track capability, should be clamped to the maximum value.
+PASS settings['width'] is 3840
 
-** Constraint: {"width":160,"height":120,"frameRate":10} - all values are less than track capabilities, should be clamped to the minimum values.
+** Constraint: {"width":160,"height":120,"frameRate":4} - all values are less than track capabilities, should be clamped to the minimum values.
 PASS settings['width'] is 320
 PASS settings['height'] is 240
-PASS settings['frameRate'] is 15
+PASS settings['frameRate'] is 5
 
 ** Constraint: {"frameRate":20} - set frame rate, width and height should remain unchanged
 PASS settings['width'] is 320
 PASS settings['height'] is 240
 PASS settings['frameRate'] is 20
 
-** Constraint: {"facingMode":"environment","height":400} - illegal facing mode value should be ignored, height should change.
+** Constraint: {"facingMode":"xnvironment","height":720} - illegal facing mode value should be ignored, height should change.
 PASS settings['facingMode'] is "user"
-PASS settings['width'] is 320
-PASS settings['height'] is 400
+PASS settings['width'] is 1280
+PASS settings['height'] is 720
 
 ** Constraint: {"WITDH":400,"frameRate":30} - unknown constraint should be ignored, frame rate should change.
-PASS settings['width'] is 320
+PASS settings['width'] is 1280
 PASS settings['frameRate'] is 30
 
-** Constraint: {"aspectRatio":"1.3333"} - aspect ratio should change width and height.
-PASS settings['width'] is 320
-PASS settings['height'] is 240
-
-** Constraint: {"aspectRatio":"1.7778"} - new aspect ratio should again change width and height.
-PASS settings['width'] is 320
-PASS settings['height'] is 180
-
-** Constraint: {"width":1920} - when aspect ratio has been set, changing width should change height.
-PASS settings['width'] is 1920
-PASS settings['height'] is 1080
-
-** Constraint: {"height":576} - when aspect ratio has been set, changing height should change width.
-PASS settings['width'] is 1024
-PASS settings['height'] is 576
-
 PASS successfullyParsed is true
 
 TEST COMPLETE
index 3d6917a..7765c48 100644 (file)
                 },
                 {
                     message: "the 'exact' constraint can be satisfied.",
-                    constraint: { width: { exact: 400 } }, 
-                    expected: { width: 400, height: 240 },
+                    constraint: { width: { exact: 960 } },
+                    expected: { width: 960, height: 540 },
                 },
                 {
-                    message: "the 'ideal' constraint can't be satisfied but the 'min' can, max should be chosen.",
+                    message: "the 'ideal' constraint can't be satisfied but the 'min' can, maximum value should be chosen.",
                     constraint: { width: {min: 300, ideal: 5000} }, 
-                    expected: { width: 1920, height: 240 },
+                    expected: { width: 3840, height: 2160 },
                 },
                 {
                     message: "'ideal' and 'min' constraints can be satisfied, 'ideal' should be chosen.",
                 },
                 {
                     message: "ideal width is greater than track capability, should be clamped to the maximum value.",
-                    constraint: { width: 3000 }, 
-                    expected: { width: 1920},
+                    constraint: { width: 5000 },
+                    expected: { width: 3840},
                 },
                 {
                     message: "all values are less than track capabilities, should be clamped to the minimum values.",
-                    constraint: { width: 160, height: 120, frameRate: 10 }, 
-                    expected: { width: 320, height: 240, frameRate: 15 },
+                    constraint: { width: 160, height: 120, frameRate: 4 },
+                    expected: { width: 320, height: 240, frameRate: 5 },
                 },
                 {
                     message: "set frame rate, width and height should remain unchanged",
                 },
                 {
                     message: "illegal facing mode value should be ignored, height should change.",
-                    constraint: { facingMode: "environment", height: 400 }, 
-                    expected: { facingMode: "user", width: 320, height: 400 },
+                    constraint: { facingMode: "xnvironment", height: 720 },
+                    expected: { facingMode: "user", width: 1280, height: 720 },
                 },
                 {
                     message: "unknown constraint should be ignored, frame rate should change.",
                     constraint: { WITDH: 400, frameRate: 30 }, 
-                    expected: { width: 320, frameRate: 30 },
-                },
-                {
-                    message: "aspect ratio should change width and height.",
-                    constraint: { aspectRatio: (4/3).toFixed(4) }, 
-                    expected: { width: 320, height: 240 },
-                },
-                {
-                    message: "new aspect ratio should again change width and height.",
-                    constraint: { aspectRatio: (16/9).toFixed(4) }, 
-                    expected: { width: 320, height: 180 },
-                },
-                {
-                    message: "when aspect ratio has been set, changing width should change height.",
-                    constraint: { width: 1920 }, 
-                    expected: { width: 1920, height: 1080},
-                },
-                {
-                    message: "when aspect ratio has been set, changing height should change width.",
-                    constraint: { height: 576 }, 
-                    expected: { width: 1024, height: 576},
+                    expected: { width: 1280, frameRate: 30 },
                 },
             ];
 
index ab4bc8f..a020da1 100644 (file)
@@ -2,6 +2,6 @@
 PASS Checking default video tracks settings 
 PASS Checking only audio capture 
 PASS Checking default video tracks settings except width and height 
-FAIL Checking default video tracks settings except height assert_equals: frame height expected 240 but got 480
+PASS Checking default video tracks settings except height 
 PASS Checking default video tracks settings except frameRate 
 
index 91883cc..b144096 100644 (file)
@@ -46,7 +46,7 @@ promise_test((test) => {
 promise_test((test) => {
     return navigator.mediaDevices.getUserMedia({ audio: true, video: { frameRate: {ideal: 60 } } }).then((stream) => {
         let settings = stream.getVideoTracks()[0].getSettings();
-        assert_equals(settings.frameRate, 60, "frame rate");
+        assert_equals(settings.frameRate, 30, "frame rate");
         assert_equals(settings.width, settings.height == 640 ? 480 : 640, "frame width");
         assert_equals(settings.height, settings.width = 640 ? 480 : 640, "frame height");
     });
index 3908637..fa05c3e 100644 (file)
@@ -2,5 +2,5 @@ When prompted, accept to share your video stream.
 
 
 PASS A device can be opened twice and have the same device ID 
-FAIL A device can be opened twice with different resolutions assert_equals: expected 640 but got 320
+PASS A device can be opened twice with different resolutions 
 
index d45a224..612f1dc 100644 (file)
@@ -45,7 +45,7 @@ promise_test((test) => {
         testRunner.setUserMediaPermission(true);
 
     var stream;
-    return navigator.mediaDevices.getUserMedia({video: {advanced: [{width:{min:1280}}, {height:{min:720} } ]}}).then((stream) => {
+    return navigator.mediaDevices.getUserMedia({video: {advanced: [{width:{min:640}}, {height:{min:480} } ]}}).then((stream) => {
         return new Promise((resolve, reject) => {
             createConnections((firstConnection) => {
                 var track = stream.getVideoTracks()[0];
index 387e7b4..4a7ca11 100644 (file)
@@ -43,7 +43,7 @@ promise_test((test) => {
     if (window.testRunner)
         testRunner.setUserMediaPermission(true);
 
-    return navigator.mediaDevices.getUserMedia({video: {advanced: [{width:{min:1280}}, {height:{min:720} } ]}}).then((stream) => {
+    return navigator.mediaDevices.getUserMedia({video: {advanced: [{width:{min:640}}, {height:{min:480} } ]}}).then((stream) => {
         if (window.internals)
             assert_true(internals.pageMediaState().includes('HasActiveVideoCaptureDevice'), "Unexpected HasActiveVideoCaptureDevice");
         return new Promise((resolve, reject) => {
@@ -66,9 +66,9 @@ promise_test((test) => {
     }).then((stream) => {
         video.srcObject = stream;
         return video.play();
-    }).then(() => {
+    }).then(test.step_func(() => {
         testImage();
-    });
+    }));
 }, "Basic video exchange");
         </script>
     </body>
index f950ca9..1c4dde3 100644 (file)
@@ -1,3 +1,115 @@
+2018-08-30  Eric Carlson  <eric.carlson@apple.com>
+
+        Mock video devices should only support discrete sizes
+        https://bugs.webkit.org/show_bug.cgi?id=189000
+        <rdar://problem/43766551>
+
+        Reviewed by Youenn Fablet.
+        
+        While many/most video capture devices only support a finite number of discrete width/height
+        pairs, our mock video capture devices supported arbitrary width and height combinations which
+        made it difficult to write realistic tests using them. Change the mock devices to support
+        finite "presets" like those supported by AVFoundation. Create a RealtimeVideoSource base
+        class with support for these presets, so the same code will eventually be used by the mock
+        and real capture devices.
+
+        No new tests, existing tests updated for these changes.
+
+        * Sources.txt: Add RealtimeVideoSource.cpp, remove MockRealtimeMediaSource.cpp.
+
+        * WebCore.xcodeproj/project.pbxproj: Ditto.
+
+        * platform/mediastream/MediaConstraints.h: Deal with min constraint less than the supported minimum
+        and max larger than the supported maximum when there is no ideal.
+
+        * platform/mediastream/RealtimeMediaSource.cpp:
+        (WebCore::RealtimeMediaSource::selectSettings): Use supportsSizeAndFrameRate for widths,
+        heights, and framerates in advanced constraints so a width and height that are supported but
+        in the same preset are filtered out.
+        (WebCore::RealtimeMediaSource::setSize): New.
+        * platform/mediastream/RealtimeMediaSource.h:
+
+        * platform/mediastream/RealtimeMediaSourceSettings.h: Remove an unneeded include.
+
+        * platform/mediastream/RealtimeVideoSource.cpp: Added.
+        (WebCore::RealtimeVideoSource::RealtimeVideoSource):
+        (WebCore::RealtimeVideoSource::~RealtimeVideoSource):
+        (WebCore::RealtimeVideoSource::startProducingData):
+        (WebCore::RealtimeVideoSource::setSupportedFrameRates):
+        (WebCore::RealtimeVideoSource::addSupportedCapabilities const):
+        (WebCore::RealtimeVideoSource::supportsSizeAndFrameRate):
+        (WebCore::RealtimeVideoSource::bestSupportedCaptureSizeForWidthAndHeight):
+        (WebCore::RealtimeVideoSource::applySize):
+        (WebCore::RealtimeVideoSource::applySizeAndFrameRate):
+        (WebCore::RealtimeVideoSource::videoSampleAvailable):
+        (WebCore::RealtimeVideoSource::applyFrameRate):
+        (WebCore::RealtimeVideoSource::supportsFrameRate):
+
+        * platform/mediastream/RealtimeVideoSource.h: Copied from Source/WebCore/platform/mock/MockRealtimeAudioSource.h.
+        (WebCore::RealtimeVideoSource::setSupportedCaptureSizes):
+        (WebCore::RealtimeVideoSource::setDefaultSize):
+        (WebCore::RealtimeVideoSource::observedFrameRate const):
+
+        * platform/mediastream/mac/AVMediaCaptureSource.mm:
+        (WebCore::AVMediaCaptureSource::initializeSettings): Don't set label, it isn't used.
+
+        * platform/mediastream/mac/MockRealtimeVideoSourceMac.mm:
+        (WebCore::MockRealtimeVideoSourceMac::applySize): Call the base class.
+
+        * platform/mock/MockMediaDevice.h:
+        (WebCore::MockCameraProperties::encode const): Add frame rates, sizes, and facing mode.
+        (WebCore::MockCameraProperties::decode): Ditto.
+
+        * platform/mock/MockRealtimeAudioSource.cpp:
+        (WebCore::MockRealtimeAudioSource::MockRealtimeAudioSource): No more MockRealtimeMediaSource.
+        (WebCore::MockRealtimeAudioSource::settings const): Clean up.
+        (WebCore::MockRealtimeAudioSource::capabilities const): Ditto.
+        (WebCore::MockRealtimeAudioSource::settingsDidChange): Ditto.
+        (WebCore::MockRealtimeAudioSource::stopProducingData): m_elapsedTime isn't used, delete it.
+        (WebCore::MockRealtimeAudioSource::updateSettings): Deleted.
+        (WebCore::MockRealtimeAudioSource::initializeCapabilities): Deleted.
+        (WebCore::MockRealtimeAudioSource::initializeSupportedConstraints): Deleted.
+        (WebCore::MockRealtimeAudioSource::elapsedTime): Deleted.
+        * platform/mock/MockRealtimeAudioSource.h:
+
+        * platform/mock/MockRealtimeMediaSourceCenter.cpp: Moved all of the mock device management
+        code from MockRealtimeMediaSource.cpp here.
+        (WebCore::defaultDevices):
+        (WebCore::devices):
+        (WebCore::deviceMap):
+        (WebCore::deviceListForDevice):
+        (WebCore::createCaptureDevice):
+        (WebCore::MockRealtimeMediaSourceCenter::resetDevices):
+        (WebCore::MockRealtimeMediaSourceCenter::setDevices):
+        (WebCore::MockRealtimeMediaSourceCenter::addDevice):
+        (WebCore::MockRealtimeMediaSourceCenter::removeDevice):
+        (WebCore::MockRealtimeMediaSourceCenter::mockDeviceWithPersistentID):
+        (WebCore::MockRealtimeMediaSourceCenter::captureDeviceWithPersistentID):
+        (WebCore::MockRealtimeMediaSourceCenter::audioDevices):
+        (WebCore::MockRealtimeMediaSourceCenter::videoDevices):
+        (WebCore::MockRealtimeMediaSourceCenter::displayDevices):
+
+        * platform/mock/MockRealtimeVideoSource.cpp:
+        (WebCore::MockRealtimeVideoSource::MockRealtimeVideoSource): Use RealtimeVideoSource, no
+        more MockRealtimeMediaSource.
+        (WebCore::MockRealtimeVideoSource::capabilities const): Ditto, cleanup.
+        (WebCore::MockRealtimeVideoSource::settings const): Ditto.
+        (WebCore::MockRealtimeVideoSource::settingsDidChange): Ditto.
+        (WebCore::MockRealtimeVideoSource::startCaptureTimer): Ditto.
+        (WebCore::MockRealtimeVideoSource::startProducingData): Ditto.
+        (WebCore::MockRealtimeVideoSource::stopProducingData): Ditto.
+        (WebCore::MockRealtimeVideoSource::elapsedTime): Ditto.
+        (WebCore::MockRealtimeVideoSource::applySize): Ditto.
+        (WebCore::MockRealtimeVideoSource::drawText): Render the actual frame rate.
+        (WebCore::MockRealtimeVideoSource::generateFrame): Use m_fillColor.
+        (WebCore::MockRealtimeVideoSource::~MockRealtimeVideoSource): Deleted.
+        (WebCore::MockRealtimeVideoSource::updateSettings): Deleted.
+        (WebCore::MockRealtimeVideoSource::initializeCapabilities): Deleted.
+        (WebCore::MockRealtimeVideoSource::initializeSupportedConstraints): Deleted.
+        (WebCore::MockRealtimeVideoSource::applyFrameRate): Deleted.
+        * platform/mock/MockRealtimeVideoSource.h:
+        (WebCore::MockRealtimeVideoSource::updateSampleBuffer): Deleted.
+
 2018-08-30  Zalan Bujtas  <zalan@apple.com>
 
         [LFC][Floating] Block formatting context roots avoid floats.
index aaf936e..3469fcd 100644 (file)
@@ -1744,6 +1744,7 @@ platform/mediastream/RealtimeMediaSourceCenter.cpp
 platform/mediastream/RealtimeMediaSourceSettings.cpp
 platform/mediastream/RealtimeOutgoingAudioSource.cpp
 platform/mediastream/RealtimeOutgoingVideoSource.cpp
+platform/mediastream/RealtimeVideoSource.cpp
 
 platform/mediastream/libwebrtc/LibWebRTCProvider.cpp
 
@@ -1752,7 +1753,6 @@ platform/mock/GeolocationClientMock.cpp
 platform/mock/MediaEngineDecodingConfigurationMock.cpp
 platform/mock/MediaEngineEncodingConfigurationMock.cpp
 platform/mock/MockRealtimeAudioSource.cpp
-platform/mock/MockRealtimeMediaSource.cpp
 platform/mock/MockRealtimeMediaSourceCenter.cpp
 platform/mock/MockRealtimeVideoSource.cpp
 platform/mock/RTCDataChannelHandlerMock.cpp
index 20e2892..f361874 100644 (file)
                07277E4F17D018CC0015534D /* JSMediaStreamAudioDestinationNode.h in Headers */ = {isa = PBXBuildFile; fileRef = 07277E4317D018CC0015534D /* JSMediaStreamAudioDestinationNode.h */; };
                07277E5317D018CC0015534D /* JSMediaStreamTrack.h in Headers */ = {isa = PBXBuildFile; fileRef = 07277E4717D018CC0015534D /* JSMediaStreamTrack.h */; };
                07277E5517D018CC0015534D /* JSMediaStreamTrackEvent.h in Headers */ = {isa = PBXBuildFile; fileRef = 07277E4917D018CC0015534D /* JSMediaStreamTrackEvent.h */; };
+               072880D12010F1F60071B255 /* RealtimeVideoSource.h in Headers */ = {isa = PBXBuildFile; fileRef = 072880D02010EED70071B255 /* RealtimeVideoSource.h */; settings = {ATTRIBUTES = (Private, ); }; };
                072A70401D6E8F6200DF0AFC /* OverconstrainedErrorEvent.h in Headers */ = {isa = PBXBuildFile; fileRef = 072A703E1D6E8F6200DF0AFC /* OverconstrainedErrorEvent.h */; };
                072AE1E5183C0741000A5988 /* PluginReplacement.h in Headers */ = {isa = PBXBuildFile; fileRef = 072AE1DF183C0741000A5988 /* PluginReplacement.h */; settings = {ATTRIBUTES = (Private, ); }; };
                072AE1E8183C0741000A5988 /* QuickTimePluginReplacement.h in Headers */ = {isa = PBXBuildFile; fileRef = 072AE1E2183C0741000A5988 /* QuickTimePluginReplacement.h */; };
                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, ); }; };
                07D637401BB0B11300256CE9 /* WebAudioSourceProviderAVFObjC.h in Headers */ = {isa = PBXBuildFile; fileRef = 07D6373E1BB0B11300256CE9 /* WebAudioSourceProviderAVFObjC.h */; settings = {ATTRIBUTES = (Private, ); }; };
-               07D6A4F01BECF2D200174146 /* MockRealtimeMediaSource.h in Headers */ = {isa = PBXBuildFile; fileRef = 07D6A4EE1BECF2D200174146 /* MockRealtimeMediaSource.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 */; };
                07E3DFD11A9E786500764CA8 /* MediaPlaybackTarget.h in Headers */ = {isa = PBXBuildFile; fileRef = 07E3DFD01A9E786500764CA8 /* MediaPlaybackTarget.h */; settings = {ATTRIBUTES = (Private, ); }; };
                07277E4817D018CC0015534D /* JSMediaStreamTrackEvent.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = JSMediaStreamTrackEvent.cpp; sourceTree = "<group>"; };
                07277E4917D018CC0015534D /* JSMediaStreamTrackEvent.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = JSMediaStreamTrackEvent.h; sourceTree = "<group>"; };
                072847E216EBC5B00043CFA4 /* PlatformTextTrack.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = PlatformTextTrack.h; sourceTree = "<group>"; };
+               072880CE2010EED60071B255 /* RealtimeVideoSource.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = RealtimeVideoSource.cpp; sourceTree = "<group>"; };
+               072880D02010EED70071B255 /* RealtimeVideoSource.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RealtimeVideoSource.h; sourceTree = "<group>"; };
                072A703E1D6E8F6200DF0AFC /* OverconstrainedErrorEvent.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = OverconstrainedErrorEvent.h; sourceTree = "<group>"; };
                072A703F1D6E8F6200DF0AFC /* OverconstrainedErrorEvent.idl */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = OverconstrainedErrorEvent.idl; sourceTree = "<group>"; };
                072AE1DF183C0741000A5988 /* PluginReplacement.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PluginReplacement.h; sourceTree = "<group>"; };
                07CE77D416712A6A00C55A47 /* InbandTextTrackPrivateClient.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = InbandTextTrackPrivateClient.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>"; };
-               07D6A4ED1BECF2D200174146 /* MockRealtimeMediaSource.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = MockRealtimeMediaSource.cpp; sourceTree = "<group>"; };
-               07D6A4EE1BECF2D200174146 /* MockRealtimeMediaSource.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MockRealtimeMediaSource.h; sourceTree = "<group>"; };
                07D6A4F11BED5F8800174146 /* MockRealtimeAudioSource.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = MockRealtimeAudioSource.cpp; sourceTree = "<group>"; };
                07D6A4F21BED5F8800174146 /* MockRealtimeAudioSource.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MockRealtimeAudioSource.h; sourceTree = "<group>"; };
                07D6A4F61BF2307D00174146 /* AudioTrackPrivateMediaStream.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = AudioTrackPrivateMediaStream.h; path = platform/mediastream/AudioTrackPrivateMediaStream.h; sourceTree = SOURCE_ROOT; };
                                41103AA81E39790A00769F03 /* RealtimeOutgoingAudioSource.h */,
                                5CDD833B1E4324BB00621E92 /* RealtimeOutgoingVideoSource.cpp */,
                                5CDD833C1E4324BB00621E92 /* RealtimeOutgoingVideoSource.h */,
+                               072880CE2010EED60071B255 /* RealtimeVideoSource.cpp */,
+                               072880D02010EED70071B255 /* RealtimeVideoSource.h */,
                                3135910C1E7DDCB600F30630 /* RTCBundlePolicy.h */,
                                07221BA217CF0AD400848E51 /* RTCDataChannelHandler.h */,
                                07221BA317CF0AD400848E51 /* RTCDataChannelHandlerClient.h */,
                                413CCD4820DE013C0065A21A /* MockMediaDevice.h */,
                                07D6A4F11BED5F8800174146 /* MockRealtimeAudioSource.cpp */,
                                07D6A4F21BED5F8800174146 /* MockRealtimeAudioSource.h */,
-                               07D6A4ED1BECF2D200174146 /* MockRealtimeMediaSource.cpp */,
-                               07D6A4EE1BECF2D200174146 /* MockRealtimeMediaSource.h */,
                                4A0FFA9B1AAF5E6C0062803B /* MockRealtimeMediaSourceCenter.cpp */,
                                4A0FFA9C1AAF5E6C0062803B /* MockRealtimeMediaSourceCenter.h */,
                                07EE76E91BE96DB000F89133 /* MockRealtimeVideoSource.cpp */,
                                CDF2B0131820540600F2B424 /* MockMediaPlayerMediaSource.h in Headers */,
                                CDF2B0151820540600F2B424 /* MockMediaSourcePrivate.h in Headers */,
                                07D6A4F41BED5F8800174146 /* MockRealtimeAudioSource.h in Headers */,
-                               07D6A4F01BECF2D200174146 /* MockRealtimeMediaSource.h in Headers */,
                                4A0FFA9E1AAF5E7E0062803B /* MockRealtimeMediaSourceCenter.h in Headers */,
                                07EE76EC1BE96DB000F89133 /* MockRealtimeVideoSource.h in Headers */,
                                07EE76EF1BEA619800F89133 /* MockRealtimeVideoSourceMac.h in Headers */,
                                07C1C0E51BFB60ED00BD2256 /* RealtimeMediaSourceSupportedConstraints.h in Headers */,
                                41103AAC1E39791000769F03 /* RealtimeOutgoingAudioSource.h in Headers */,
                                41103AAC1E39791000769F14 /* RealtimeOutgoingAudioSourceCocoa.h in Headers */,
+                               072880D12010F1F60071B255 /* RealtimeVideoSource.h in Headers */,
                                91B952241F58A58F00931DC2 /* RecordingSwizzleTypes.h in Headers */,
                                BC4368E80C226E32005EFB5F /* Rect.h in Headers */,
                                FD45A958175D414C00C21EC8 /* RectangleShape.h in Headers */,
index 056fc7e..65e96ac 100644 (file)
@@ -254,6 +254,8 @@ public:
             ASSERT(validForRange(value, capabilityMax));
             if (value > min)
                 min = value;
+            if (value < min)
+                value = min;
 
             // If there is no ideal, don't change if minimum is smaller than current.
             if (!m_ideal && value < current)
@@ -265,6 +267,8 @@ public:
             ASSERT(validForRange(capabilityMin, value));
             if (value < max)
                 max = value;
+            if (value > max)
+                value = max;
         }
 
         if (m_ideal)
index cadaf75..2e9d965 100644 (file)
@@ -651,7 +651,19 @@ bool RealtimeMediaSource::selectSettings(const MediaConstraints& constraints, Fl
         double constraintDistance = 0;
         bool supported = false;
 
+        if (advancedConstraint.width() || advancedConstraint.height() || advancedConstraint.frameRate()) {
+            String dummy;
+            if (!supportsSizeAndFrameRate(advancedConstraint.width(), advancedConstraint.height(), advancedConstraint.frameRate(), dummy, constraintDistance))
+                continue;
+
+            supported = true;
+        }
+
         advancedConstraint.forEach([&](const MediaConstraint& constraint) {
+
+            if (constraint.constraintType() == MediaConstraintType::Width || constraint.constraintType() == MediaConstraintType::Height || constraint.constraintType() == MediaConstraintType::FrameRate)
+                return;
+
             distance = fitnessDistance(constraint);
             constraintDistance += distance;
             if (!std::isinf(distance))
@@ -848,6 +860,18 @@ void RealtimeMediaSource::applyConstraints(const MediaConstraints& constraints,
         failureHandler(result.value().first, result.value().second);
 }
 
+void RealtimeMediaSource::setSize(const IntSize& size)
+{
+    if (size == m_size)
+        return;
+
+    if (!applySize(size))
+        return;
+
+    m_size = size;
+    settingsDidChange();
+}
+
 void RealtimeMediaSource::setWidth(int width)
 {
     if (width == m_size.width())
index c29ab19..48419ba 100644 (file)
@@ -167,6 +167,7 @@ public:
 
     void setWidth(int);
     void setHeight(int);
+    void setSize(const IntSize&);
     const IntSize& size() const { return m_size; }
     virtual bool applySize(const IntSize&) { return false; }
 
diff --git a/Source/WebCore/platform/mediastream/RealtimeVideoSource.cpp b/Source/WebCore/platform/mediastream/RealtimeVideoSource.cpp
new file mode 100644 (file)
index 0000000..2d1faea
--- /dev/null
@@ -0,0 +1,188 @@
+/*
+ * Copyright (C) 2018 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+#include "RealtimeVideoSource.h"
+
+#if ENABLE(MEDIA_STREAM)
+#include "CaptureDevice.h"
+#include "Logging.h"
+#include "RealtimeMediaSourceCenter.h"
+#include "RealtimeMediaSourceSettings.h"
+
+namespace WebCore {
+
+RealtimeVideoSource::RealtimeVideoSource(const String& id, const String& name)
+    : RealtimeMediaSource(id, Type::Video, name)
+{
+}
+
+RealtimeVideoSource::~RealtimeVideoSource()
+{
+#if PLATFORM(IOS)
+    RealtimeMediaSourceCenter::singleton().videoFactory().unsetActiveSource(*this);
+#endif
+}
+
+void RealtimeVideoSource::prepareToProduceData()
+{
+    ASSERT(frameRate());
+
+#if PLATFORM(IOS)
+    RealtimeMediaSourceCenter::singleton().videoFactory().setActiveSource(*this);
+#endif
+
+    if (size().isEmpty() && !m_defaultSize.isEmpty())
+        setSize(m_defaultSize);
+}
+
+void RealtimeVideoSource::setSupportedFrameRates(Vector<double>&& rates)
+{
+    m_supportedFrameRates = WTFMove(rates);
+    std::sort(m_supportedFrameRates.begin(), m_supportedFrameRates.end());
+}
+
+void RealtimeVideoSource::addSupportedCapabilities(RealtimeMediaSourceCapabilities& capabilities) const
+{
+    ASSERT(!m_supportedCaptureSizes.isEmpty());
+    ASSERT(!m_supportedFrameRates.isEmpty());
+
+    capabilities.setFrameRate({ m_supportedFrameRates[0], m_supportedFrameRates[m_supportedFrameRates.size() - 1] });
+
+    int minimumWidth = std::numeric_limits<int>::max();
+    int maximumWidth = 0;
+    int minimumHeight = std::numeric_limits<int>::max();
+    int maximumHeight = 0;
+    float minimumAspectRatio = std::numeric_limits<float>::max();
+    float maximumAspectRatio = 0;
+    for (const auto& size : m_supportedCaptureSizes) {
+        minimumWidth = std::min(minimumWidth, size.width());
+        maximumWidth = std::max(maximumWidth, size.width());
+
+        minimumHeight = std::min(minimumHeight, size.height());
+        maximumHeight = std::max(maximumHeight, size.height());
+
+        minimumAspectRatio = std::min(minimumAspectRatio, size.aspectRatio());
+        maximumAspectRatio = std::max(maximumAspectRatio, size.aspectRatio());
+    }
+
+    capabilities.setWidth({ minimumWidth, maximumWidth });
+    capabilities.setHeight({ minimumHeight, maximumHeight });
+    capabilities.setAspectRatio({ minimumAspectRatio, maximumAspectRatio });
+}
+
+bool RealtimeVideoSource::supportsSizeAndFrameRate(std::optional<int> width, std::optional<int> height, std::optional<double> frameRate)
+{
+    if (!height && !width && !frameRate)
+        return true;
+
+    if (height || width) {
+        if (m_supportedCaptureSizes.isEmpty())
+            return false;
+
+        if (bestSupportedCaptureSizeForWidthAndHeight(width, height).isEmpty())
+            return false;
+    }
+
+    if (!frameRate)
+        return true;
+
+    return supportsFrameRate(frameRate.value());
+}
+
+IntSize RealtimeVideoSource::bestSupportedCaptureSizeForWidthAndHeight(std::optional<int> width, std::optional<int> height)
+{
+    if (!width && !height)
+        return { };
+
+    for (auto size : m_supportedCaptureSizes) {
+        if ((!width || width.value() == size.width()) && (!height || height.value() == size.height()))
+            return size;
+    }
+
+    return { };
+}
+
+bool RealtimeVideoSource::applySize(const IntSize& size)
+{
+    IntSize supportedSize = bestSupportedCaptureSizeForWidthAndHeight(size.width(), size.height());
+    if (supportedSize.isEmpty()) {
+        LOG(Media, "RealtimeVideoSource::applySize(%p), unable find or set preset for width: %i, height: %i", this, size.width(), size.height());
+        return false;
+    }
+
+    return true;
+}
+
+void RealtimeVideoSource::applySizeAndFrameRate(std::optional<int> width, std::optional<int> height, std::optional<double> frameRate)
+{
+    if (width || height) {
+        IntSize supportedSize = bestSupportedCaptureSizeForWidthAndHeight(WTFMove(width), WTFMove(height));
+        ASSERT(!supportedSize.isEmpty());
+        if (!supportedSize.isEmpty())
+            setSize(supportedSize);
+    }
+
+    if (frameRate)
+        setFrameRate(frameRate.value());
+}
+
+void RealtimeVideoSource::dispatchMediaSampleToObservers(MediaSample& sample)
+{
+    MediaTime sampleTime = sample.outputPresentationTime();
+    if (!sampleTime || !sampleTime.isValid())
+        sampleTime = sample.presentationTime();
+
+    auto frameTime = sampleTime.toDouble();
+    m_observedFrameTimeStamps.append(frameTime);
+    m_observedFrameTimeStamps.removeAllMatching([&](auto time) {
+        return time <= frameTime - 2;
+    });
+
+    auto interval = m_observedFrameTimeStamps.last() - m_observedFrameTimeStamps.first();
+    if (interval > 1)
+        m_observedFrameRate = (m_observedFrameTimeStamps.size() / interval);
+
+    videoSampleAvailable(sample);
+}
+
+bool RealtimeVideoSource::applyFrameRate(double rate)
+{
+    return supportsFrameRate(rate);
+}
+
+bool RealtimeVideoSource::supportsFrameRate(double frameRate)
+{
+    double epsilon = 0.001;
+    for (auto rate : m_supportedFrameRates) {
+        if (frameRate + epsilon >= rate && frameRate - epsilon <= rate)
+            return true;
+    }
+    return false;
+}
+
+} // namespace WebCore
+
+#endif // ENABLE(MEDIA_STREAM)
diff --git a/Source/WebCore/platform/mediastream/RealtimeVideoSource.h b/Source/WebCore/platform/mediastream/RealtimeVideoSource.h
new file mode 100644 (file)
index 0000000..1c257f6
--- /dev/null
@@ -0,0 +1,77 @@
+/*
+ * Copyright (C) 2018 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#pragma once
+
+#if ENABLE(MEDIA_STREAM)
+
+#include "FontCascade.h"
+#include "ImageBuffer.h"
+#include "MediaSample.h"
+#include "RealtimeMediaSource.h"
+#include <wtf/Lock.h>
+#include <wtf/RunLoop.h>
+
+namespace WebCore {
+
+class RealtimeVideoSource : public RealtimeMediaSource {
+public:
+    virtual ~RealtimeVideoSource();
+
+protected:
+    RealtimeVideoSource(const String& id, const String& name);
+
+    void prepareToProduceData();
+    bool supportsSizeAndFrameRate(std::optional<int> width, std::optional<int> height, std::optional<double>) final;
+    void applySizeAndFrameRate(std::optional<int> width, std::optional<int> height, std::optional<double>) final;
+    bool applySize(const IntSize&) override;
+    bool applyFrameRate(double) final;
+
+    void setSupportedFrameRates(Vector<double>&&);
+    void setSupportedCaptureSizes(const Vector<IntSize>&& sizes) { m_supportedCaptureSizes = sizes; }
+    IntSize bestSupportedCaptureSizeForWidthAndHeight(std::optional<int> width, std::optional<int> height);
+
+    void addSupportedCapabilities(RealtimeMediaSourceCapabilities&) const;
+
+    void setDefaultSize(const IntSize& size) { m_defaultSize = size; }
+
+    double observedFrameRate() const { return m_observedFrameRate; }
+
+    void dispatchMediaSampleToObservers(MediaSample&);
+
+private:
+    bool supportsFrameRate(double);
+
+    Vector<IntSize> m_supportedCaptureSizes;
+    Vector<double> m_supportedFrameRates;
+    Deque<double> m_observedFrameTimeStamps;
+    double m_observedFrameRate { 0 };
+    IntSize m_defaultSize;
+};
+
+} // namespace WebCore
+
+#endif // ENABLE(MEDIA_STREAM)
+
index dc80276..ed3227f 100644 (file)
@@ -24,7 +24,6 @@
 #if ENABLE(MEDIA_STREAM) && USE(LIBWEBRTC) && USE(GSTREAMER)
 
 #include "GStreamerVideoCaptureSource.h"
-#include "MockRealtimeMediaSource.h"
 
 namespace WebCore {
 
index 9824aa7..2c114eb 100644 (file)
@@ -213,7 +213,6 @@ void AVMediaCaptureSource::initializeSettings()
         m_currentSettings.setSupportedConstraints(supportedConstraints());
 
     m_currentSettings.setDeviceId(id());
-    m_currentSettings.setLabel(name());
     updateSettings(m_currentSettings);
 }
 
index 0b4229d..5abb8f2 100644 (file)
@@ -36,6 +36,7 @@
 #import "CAAudioStreamDescription.h"
 #import "MediaConstraints.h"
 #import "MediaSampleAVFObjC.h"
+#import "MockRealtimeMediaSourceCenter.h"
 #import "NotImplemented.h"
 #import "RealtimeMediaSourceSettings.h"
 #import "WebAudioBufferList.h"
index 68e6765..f583671 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2015 Apple Inc. All rights reserved.
+ * Copyright (C) 2015-2018 Apple Inc. All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions
index 7e7ca7d..4ccee19 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2015 Apple Inc. All rights reserved.
+ * Copyright (C) 2015-2018 Apple Inc. All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions
@@ -151,15 +151,16 @@ void MockRealtimeVideoSourceMac::updateSampleBuffer()
     auto sampleBuffer = CMSampleBufferFromPixelBuffer(pixelBuffer.get());
 
     // We use m_deviceOrientation to emulate sensor orientation
-    videoSampleAvailable(MediaSampleAVFObjC::create(sampleBuffer.get(), m_deviceOrientation));
+    dispatchMediaSampleToObservers(MediaSampleAVFObjC::create(sampleBuffer.get(), m_deviceOrientation));
 }
 
 bool MockRealtimeVideoSourceMac::applySize(const IntSize& newSize)
 {
-    if (size() != newSize)
-        m_bufferPool = nullptr;
+    if (!MockRealtimeVideoSource::applySize(newSize))
+        return false;
 
-    return MockRealtimeVideoSource::applySize(newSize);
+    m_bufferPool = nullptr;
+    return true;
 }
 
 void MockRealtimeVideoSourceMac::orientationChanged(int orientation)
index 882dbaf..1d03c5a 100644 (file)
@@ -60,7 +60,9 @@ struct MockCameraProperties {
     void encode(Encoder& encoder) const
     {
         encoder << defaultFrameRate;
-        encoder << facingModeCapability;
+        encoder << facingMode;
+        encoder << frameRates;
+        encoder << frameSizes;
     }
 
     template <class Decoder>
@@ -71,16 +73,28 @@ struct MockCameraProperties {
         if (!defaultFrameRate)
             return std::nullopt;
 
-        std::optional<RealtimeMediaSourceSettings::VideoFacingMode> facingModeCapability;
-        decoder >> facingModeCapability;
-        if (!facingModeCapability)
+        std::optional<RealtimeMediaSourceSettings::VideoFacingMode> facingMode;
+        decoder >> facingMode;
+        if (!facingMode)
             return std::nullopt;
 
-        return MockCameraProperties { *defaultFrameRate, *facingModeCapability, Color::black };
+        std::optional<Vector<double>> frameRates;
+        decoder >> frameRates;
+        if (!frameRates)
+            return std::nullopt;
+
+        std::optional<Vector<IntSize>> frameSizes;
+        decoder >> frameSizes;
+        if (!frameSizes)
+            return std::nullopt;
+
+        return MockCameraProperties { *defaultFrameRate, *facingMode, WTFMove(*frameRates), WTFMove(*frameSizes), Color::black };
     }
 
     double defaultFrameRate { 30 };
-    RealtimeMediaSourceSettings::VideoFacingMode facingModeCapability { RealtimeMediaSourceSettings::VideoFacingMode::User };
+    RealtimeMediaSourceSettings::VideoFacingMode facingMode { RealtimeMediaSourceSettings::VideoFacingMode::User };
+    Vector<double> frameRates { 30, 15 };
+    Vector<IntSize> frameSizes { { 640, 480 }, { 352, 288 }, { 320, 240 } };
     Color fillColor { Color::black };
 };
 
index 002caf3..f3c937f 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2015-2017 Apple Inc. All rights reserved.
+ * Copyright (C) 2015-2018 Apple Inc. All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions
@@ -47,7 +47,7 @@ class MockRealtimeAudioSourceFactory : public RealtimeMediaSource::AudioCaptureF
 public:
     CaptureSourceOrError createAudioCaptureSource(const CaptureDevice& device, const MediaConstraints* constraints) final
     {
-        for (auto& mockDevice : MockRealtimeMediaSource::audioDevices()) {
+        for (auto& mockDevice : MockRealtimeMediaSourceCenter::audioDevices()) {
             if (mockDevice.persistentId() == device.persistentId())
                 return MockRealtimeAudioSource::create(mockDevice.persistentId(), mockDevice.label(), constraints);
         }
@@ -58,7 +58,12 @@ public:
 #if !PLATFORM(MAC) && !PLATFORM(IOS) && !(USE(GSTREAMER) && USE(LIBWEBRTC))
 CaptureSourceOrError MockRealtimeAudioSource::create(const String& deviceID, const String& name, const MediaConstraints* constraints)
 {
-    auto source = adoptRef(*new MockRealtimeAudioSource(deviceID, name));
+    auto device = MockRealtimeMediaSourceCenter::mockDeviceWithPersistentID(deviceID);
+    ASSERT(device);
+    if (!device)
+        return { };
+
+    auto source = adoptRef(*new MockRealtimeAudioSource(WTFMove(device), deviceID, name));
     if (constraints && source->applyConstraints(*constraints))
         return { };
 
@@ -78,9 +83,12 @@ RealtimeMediaSource::AudioCaptureFactory& MockRealtimeAudioSource::factory()
 }
 
 MockRealtimeAudioSource::MockRealtimeAudioSource(const String& deviceID, const String& name)
-    : MockRealtimeMediaSource(deviceID, RealtimeMediaSource::Type::Audio, name)
+    : RealtimeMediaSource(deviceID, RealtimeMediaSource::Type::Audio, name)
     , m_timer(RunLoop::current(), this, &MockRealtimeAudioSource::tick)
 {
+    auto device = MockRealtimeMediaSourceCenter::mockDeviceWithPersistentID(deviceID);
+    ASSERT(device);
+    m_device = *device;
 }
 
 MockRealtimeAudioSource::~MockRealtimeAudioSource()
@@ -90,25 +98,46 @@ MockRealtimeAudioSource::~MockRealtimeAudioSource()
 #endif
 }
 
-void MockRealtimeAudioSource::updateSettings(RealtimeMediaSourceSettings& settings)
+const RealtimeMediaSourceSettings& MockRealtimeAudioSource::settings() const
 {
-    settings.setVolume(volume());
-    settings.setEchoCancellation(echoCancellation());
-    settings.setSampleRate(sampleRate());
+    if (!m_currentSettings) {
+        RealtimeMediaSourceSettings settings;
+        settings.setDeviceId(id());
+        settings.setVolume(volume());
+        settings.setEchoCancellation(echoCancellation());
+        settings.setSampleRate(sampleRate());
+
+        RealtimeMediaSourceSupportedConstraints supportedConstraints;
+        supportedConstraints.setSupportsDeviceId(true);
+        supportedConstraints.setSupportsVolume(true);
+        supportedConstraints.setSupportsEchoCancellation(true);
+        supportedConstraints.setSupportsSampleRate(true);
+        settings.setSupportedConstraints(supportedConstraints);
+
+        m_currentSettings = WTFMove(settings);
+    }
+    return m_currentSettings.value();
 }
 
-void MockRealtimeAudioSource::initializeCapabilities(RealtimeMediaSourceCapabilities& capabilities)
+const RealtimeMediaSourceCapabilities& MockRealtimeAudioSource::capabilities() const
 {
-    capabilities.setVolume(CapabilityValueOrRange(0.0, 1.0));
-    capabilities.setEchoCancellation(RealtimeMediaSourceCapabilities::EchoCancellation::ReadWrite);
-    capabilities.setSampleRate(CapabilityValueOrRange(44100, 48000));
+    if (!m_capabilities) {
+        RealtimeMediaSourceCapabilities capabilities(settings().supportedConstraints());
+
+        capabilities.setDeviceId(id());
+        capabilities.setVolume(CapabilityValueOrRange(0.0, 1.0));
+        capabilities.setEchoCancellation(RealtimeMediaSourceCapabilities::EchoCancellation::ReadWrite);
+        capabilities.setSampleRate(CapabilityValueOrRange(44100, 48000));
+
+        m_capabilities = WTFMove(capabilities);
+    }
+    return m_capabilities.value();
 }
 
-void MockRealtimeAudioSource::initializeSupportedConstraints(RealtimeMediaSourceSupportedConstraints& supportedConstraints)
+void MockRealtimeAudioSource::settingsDidChange()
 {
-    supportedConstraints.setSupportsVolume(true);
-    supportedConstraints.setSupportsEchoCancellation(true);
-    supportedConstraints.setSupportsSampleRate(true);
+    m_currentSettings = std::nullopt;
+    RealtimeMediaSource::settingsDidChange();
 }
 
 void MockRealtimeAudioSource::startProducingData()
@@ -118,7 +147,7 @@ void MockRealtimeAudioSource::startProducingData()
 #endif
 
     if (!sampleRate())
-        setSampleRate(WTF::get<MockMicrophoneProperties>(device().properties).defaultSampleRate);
+        setSampleRate(WTF::get<MockMicrophoneProperties>(m_device.properties).defaultSampleRate);
 
     m_startTime = MonotonicTime::now();
     m_timer.startRepeating(renderInterval());
@@ -127,18 +156,9 @@ void MockRealtimeAudioSource::startProducingData()
 void MockRealtimeAudioSource::stopProducingData()
 {
     m_timer.stop();
-    m_elapsedTime += MonotonicTime::now() - m_startTime;
     m_startTime = MonotonicTime::nan();
 }
 
-Seconds MockRealtimeAudioSource::elapsedTime()
-{
-    if (std::isnan(m_startTime))
-        return m_elapsedTime;
-
-    return m_elapsedTime + (MonotonicTime::now() - m_startTime);
-}
-
 void MockRealtimeAudioSource::tick()
 {
     if (std::isnan(m_lastRenderTime))
index 381a444..443dd07 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2015-2017 Apple Inc. All rights reserved.
+ * Copyright (C) 2015-2018 Apple Inc. All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions
 #if ENABLE(MEDIA_STREAM)
 
 #include "ImageBuffer.h"
-#include "MockRealtimeMediaSource.h"
+#include "MockMediaDevice.h"
 #include <wtf/RunLoop.h>
 
 namespace WebCore {
 
-class MockRealtimeAudioSource : public MockRealtimeMediaSource {
+class MockRealtimeAudioSource : public RealtimeMediaSource {
 public:
 
     static CaptureSourceOrError create(const String& deviceID, const String& name, const MediaConstraints*);
@@ -55,19 +55,17 @@ protected:
 
     virtual void render(Seconds) { }
 
-    Seconds elapsedTime();
     static Seconds renderInterval() { return 60_ms; }
 
 private:
-
     bool applyVolume(double) override { return true; }
     bool applySampleRate(int) override { return true; }
     bool applySampleSize(int) override { return true; }
     bool applyEchoCancellation(bool) override { return true; }
 
-    void updateSettings(RealtimeMediaSourceSettings&) override;
-    void initializeCapabilities(RealtimeMediaSourceCapabilities&) override;
-    void initializeSupportedConstraints(RealtimeMediaSourceSupportedConstraints&) override;
+    const RealtimeMediaSourceCapabilities& capabilities() const final;
+    const RealtimeMediaSourceSettings& settings() const final;
+    void settingsDidChange() final;
 
     void tick();
 
@@ -75,11 +73,16 @@ private:
 
     void delaySamples(Seconds) final;
 
+    mutable std::optional<RealtimeMediaSourceCapabilities> m_capabilities;
+    mutable std::optional<RealtimeMediaSourceSettings> m_currentSettings;
+    RealtimeMediaSourceSupportedConstraints m_supportedConstraints;
+
     RunLoop::Timer<MockRealtimeAudioSource> m_timer;
     MonotonicTime m_startTime { MonotonicTime::nan() };
     MonotonicTime m_lastRenderTime { MonotonicTime::nan() };
     Seconds m_elapsedTime { 0_s };
     MonotonicTime m_delayUntil;
+    MockMediaDevice m_device;
 };
 
 } // namespace WebCore
diff --git a/Source/WebCore/platform/mock/MockRealtimeMediaSource.cpp b/Source/WebCore/platform/mock/MockRealtimeMediaSource.cpp
deleted file mode 100644 (file)
index ec441ef..0000000
+++ /dev/null
@@ -1,255 +0,0 @@
-/*
- * Copyright (C) 2015 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.
- * 3. Neither the name of Google Inc. nor the names of its contributors
- *    may be used to endorse or promote products derived from this
- *    software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-#include "config.h"
-#include "MockRealtimeMediaSource.h"
-
-#if ENABLE(MEDIA_STREAM)
-
-#include "CaptureDevice.h"
-#include "Logging.h"
-#include "MediaConstraints.h"
-#include "NotImplemented.h"
-#include "RealtimeMediaSourceSettings.h"
-#include <math.h>
-#include <wtf/NeverDestroyed.h>
-#include <wtf/text/StringView.h>
-
-namespace WebCore {
-
-static inline Vector<MockMediaDevice> defaultDevices()
-{
-    return Vector<MockMediaDevice> {
-        MockMediaDevice { "239c24b0-2b15-11e3-8224-0800200c9a66"_s, "Mock audio device 1"_s, MockMicrophoneProperties { 44100 } },
-        MockMediaDevice { "239c24b1-2b15-11e3-8224-0800200c9a66"_s, "Mock audio device 2"_s, MockMicrophoneProperties { 48000 } },
-
-        MockMediaDevice { "239c24b2-2b15-11e3-8224-0800200c9a66"_s, "Mock video device 1"_s, MockCameraProperties { 30, RealtimeMediaSourceSettings::VideoFacingMode::User, Color::black } },
-        MockMediaDevice { "239c24b3-2b15-11e3-8224-0800200c9a66"_s, "Mock video device 2"_s, MockCameraProperties { 15, RealtimeMediaSourceSettings::VideoFacingMode::Environment, Color::darkGray } },
-
-        MockMediaDevice { "SCREEN-1"_s, "Mock screen device 1"_s, MockDisplayProperties { 30, Color::lightGray } },
-        MockMediaDevice { "SCREEN-2"_s, "Mock screen device 2"_s, MockDisplayProperties { 10, Color::yellow } }
-    };
-}
-
-static Vector<MockMediaDevice>& devices()
-{
-    static auto devices = makeNeverDestroyed([] {
-        return defaultDevices();
-    }());
-    return devices;
-}
-
-static HashMap<String, MockMediaDevice>& deviceMap()
-{
-    static auto map = makeNeverDestroyed([] {
-        HashMap<String, MockMediaDevice> map;
-        for (auto& device : devices())
-            map.add(device.persistentId, device);
-
-        return map;
-    }());
-    return map;
-}
-
-static inline Vector<CaptureDevice>& deviceListForDevice(const MockMediaDevice& device)
-{
-    if (device.isMicrophone())
-        return MockRealtimeAudioSource::audioDevices();
-    if (device.isCamera())
-        return MockRealtimeAudioSource::videoDevices();
-
-    ASSERT(device.isDisplay());
-    return MockRealtimeAudioSource::displayDevices();
-}
-
-void MockRealtimeMediaSource::createCaptureDevice(const MockMediaDevice& device)
-{
-    deviceListForDevice(device).append(captureDeviceWithPersistentID(device.type(), device.persistentId).value());
-}
-
-void MockRealtimeMediaSource::resetDevices()
-{
-    setDevices(defaultDevices());
-    RealtimeMediaSourceCenter::singleton().captureDevicesChanged();
-}
-
-void MockRealtimeMediaSource::setDevices(Vector<MockMediaDevice>&& newMockDevices)
-{
-    audioDevices().clear();
-    videoDevices().clear();
-    displayDevices().clear();
-
-    auto& mockDevices = devices();
-    mockDevices = WTFMove(newMockDevices);
-
-    auto& map = deviceMap();
-    map.clear();
-
-    for (const auto& device : mockDevices) {
-        map.add(device.persistentId, device);
-        createCaptureDevice(device);
-    }
-    RealtimeMediaSourceCenter::singleton().captureDevicesChanged();
-}
-
-void MockRealtimeMediaSource::addDevice(const MockMediaDevice& device)
-{
-    devices().append(device);
-    deviceMap().set(device.persistentId, device);
-    createCaptureDevice(device);
-    RealtimeMediaSourceCenter::singleton().captureDevicesChanged();
-}
-
-void MockRealtimeMediaSource::removeDevice(const String& persistentId)
-{
-    auto& map = deviceMap();
-    auto iterator = map.find(persistentId);
-    if (iterator == map.end())
-        return;
-
-    devices().removeFirstMatching([&persistentId](const auto& device) {
-        return device.persistentId == persistentId;
-    });
-
-    deviceListForDevice(iterator->value).removeFirstMatching([&persistentId](const auto& device) {
-        return device.persistentId() == persistentId;
-    });
-
-    map.remove(iterator);
-    RealtimeMediaSourceCenter::singleton().captureDevicesChanged();
-}
-
-std::optional<CaptureDevice> MockRealtimeMediaSource::captureDeviceWithPersistentID(CaptureDevice::DeviceType type, const String& id)
-{
-    ASSERT(!id.isEmpty());
-
-    auto& map = deviceMap();
-    auto iterator = map.find(id);
-    if (iterator == map.end() || iterator->value.type() != type)
-        return std::nullopt;
-
-    CaptureDevice device { iterator->value.persistentId, type, iterator->value.label };
-    device.setEnabled(true);
-    return WTFMove(device);
-}
-
-Vector<CaptureDevice>& MockRealtimeMediaSource::audioDevices()
-{
-    static auto audioDevices = makeNeverDestroyed([] {
-        Vector<CaptureDevice> audioDevices;
-        for (const auto& device : devices()) {
-            if (device.type() == CaptureDevice::DeviceType::Microphone)
-                audioDevices.append(captureDeviceWithPersistentID(CaptureDevice::DeviceType::Microphone, device.persistentId).value());
-        }
-        return audioDevices;
-    }());
-    return audioDevices;
-}
-
-Vector<CaptureDevice>& MockRealtimeMediaSource::videoDevices()
-{
-    static auto videoDevices = makeNeverDestroyed([] {
-        Vector<CaptureDevice> videoDevices;
-        for (const auto& device : devices()) {
-            if (device.type() == CaptureDevice::DeviceType::Camera)
-                videoDevices.append(captureDeviceWithPersistentID(CaptureDevice::DeviceType::Camera, device.persistentId).value());
-        }
-        return videoDevices;
-    }());
-    return videoDevices;
-}
-
-Vector<CaptureDevice>& MockRealtimeMediaSource::displayDevices()
-{
-    static auto displayDevices = makeNeverDestroyed([] {
-        Vector<CaptureDevice> displayDevices;
-        for (const auto& device : devices()) {
-            if (device.type() == CaptureDevice::DeviceType::Screen)
-                displayDevices.append(captureDeviceWithPersistentID(CaptureDevice::DeviceType::Screen, device.persistentId).value());
-        }
-        return displayDevices;
-    }());
-
-    return displayDevices;
-}
-
-MockRealtimeMediaSource::MockRealtimeMediaSource(const String& id, RealtimeMediaSource::Type type, const String& name)
-    : RealtimeMediaSource(id, type, name)
-    , m_device(deviceMap().get(id))
-{
-    ASSERT(type != RealtimeMediaSource::Type::None);
-    setPersistentID(String(id));
-}
-
-void MockRealtimeMediaSource::initializeCapabilities()
-{
-    m_capabilities = std::make_unique<RealtimeMediaSourceCapabilities>(supportedConstraints());
-    m_capabilities->setDeviceId(id());
-    initializeCapabilities(*m_capabilities.get());
-}
-
-const RealtimeMediaSourceCapabilities& MockRealtimeMediaSource::capabilities() const
-{
-    if (!m_capabilities)
-        const_cast<MockRealtimeMediaSource&>(*this).initializeCapabilities();
-    return *m_capabilities;
-}
-
-void MockRealtimeMediaSource::initializeSettings()
-{
-    if (m_currentSettings.deviceId().isEmpty()) {
-        m_currentSettings.setSupportedConstraints(supportedConstraints());
-        m_currentSettings.setDeviceId(id());
-        m_currentSettings.setLabel(name());
-    }
-
-    updateSettings(m_currentSettings);
-}
-
-const RealtimeMediaSourceSettings& MockRealtimeMediaSource::settings() const
-{
-    const_cast<MockRealtimeMediaSource&>(*this).initializeSettings();
-    return m_currentSettings;
-}
-
-RealtimeMediaSourceSupportedConstraints& MockRealtimeMediaSource::supportedConstraints()
-{
-    if (m_supportedConstraints.supportsDeviceId())
-        return m_supportedConstraints;
-
-    m_supportedConstraints.setSupportsDeviceId(true);
-    initializeSupportedConstraints(m_supportedConstraints);
-
-    return m_supportedConstraints;
-}
-
-} // namespace WebCore
-
-#endif // ENABLE(MEDIA_STREAM)
diff --git a/Source/WebCore/platform/mock/MockRealtimeMediaSource.h b/Source/WebCore/platform/mock/MockRealtimeMediaSource.h
deleted file mode 100644 (file)
index 3355da6..0000000
+++ /dev/null
@@ -1,84 +0,0 @@
-/*
- * Copyright (C) 2015 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.
- * 3. Neither the name of Ericsson nor the names of its contributors
- *    may be used to endorse or promote products derived from this
- *    software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-#pragma once
-
-#if ENABLE(MEDIA_STREAM)
-
-#include "CaptureDevice.h"
-#include "MockMediaDevice.h"
-#include "RealtimeMediaSource.h"
-
-namespace WebCore {
-
-class MockRealtimeMediaSource : public RealtimeMediaSource {
-public:
-    virtual ~MockRealtimeMediaSource() = default;
-
-    static void setDevices(Vector<MockMediaDevice>&&);
-    static void addDevice(const MockMediaDevice&);
-    static void removeDevice(const String& persistentId);
-    WEBCORE_EXPORT static void resetDevices();
-
-    static Vector<CaptureDevice>& audioDevices();
-    static Vector<CaptureDevice>& videoDevices();
-    static Vector<CaptureDevice>& displayDevices();
-
-    static std::optional<CaptureDevice> captureDeviceWithPersistentID(CaptureDevice::DeviceType, const String&);
-
-protected:
-    MockRealtimeMediaSource(const String& id, Type, const String& name);
-
-    static void createCaptureDevice(const MockMediaDevice&);
-
-    virtual void updateSettings(RealtimeMediaSourceSettings&) = 0;
-    virtual void initializeCapabilities(RealtimeMediaSourceCapabilities&) = 0;
-    virtual void initializeSupportedConstraints(RealtimeMediaSourceSupportedConstraints&) = 0;
-
-    const RealtimeMediaSourceCapabilities& capabilities() const override;
-    const RealtimeMediaSourceSettings& settings() const override;
-
-    RealtimeMediaSourceSupportedConstraints& supportedConstraints();
-
-    const MockMediaDevice& device() const { return m_device; }
-    MockMediaDevice m_device;
-
-private:
-    void initializeCapabilities();
-    void initializeSettings();
-
-    RealtimeMediaSourceSettings m_currentSettings;
-    RealtimeMediaSourceSupportedConstraints m_supportedConstraints;
-    std::unique_ptr<RealtimeMediaSourceCapabilities> m_capabilities;
-};
-
-} // namespace WebCore
-
-#endif // ENABLE(MEDIA_STREAM)
index db68821..d9ab733 100644 (file)
 
 #if ENABLE(MEDIA_STREAM)
 
+#include "CaptureDevice.h"
 #include "Logging.h"
+#include "MediaConstraints.h"
 #include "MockRealtimeAudioSource.h"
 #include "MockRealtimeVideoSource.h"
+#include "NotImplemented.h"
+#include "RealtimeMediaSourceSettings.h"
+#include <math.h>
 #include <wtf/NeverDestroyed.h>
+#include <wtf/text/StringView.h>
 
 namespace WebCore {
 
+static inline Vector<MockMediaDevice> defaultDevices()
+{
+    return Vector<MockMediaDevice> {
+        MockMediaDevice { "239c24b0-2b15-11e3-8224-0800200c9a66"_s, "Mock audio device 1"_s, MockMicrophoneProperties { 44100 } },
+        MockMediaDevice { "239c24b1-2b15-11e3-8224-0800200c9a66"_s, "Mock audio device 2"_s, MockMicrophoneProperties { 48000 } },
+
+        MockMediaDevice { "239c24b2-2b15-11e3-8224-0800200c9a66"_s, "Mock video device 1"_s,
+            MockCameraProperties {
+                30,
+                RealtimeMediaSourceSettings::VideoFacingMode::User,
+                { 30.00, 27.50, 25.00, 22.50, 20.00, 17.50, 15.00, 12.50, 10.00, 7.50, 5.00 },
+                { { 3840, 2160 }, { 1920, 1080 }, { 1280, 720 }, { 960, 540 }, { 640, 480 }, { 352, 288 }, { 320, 240 } },
+                Color::black,
+            } },
+
+        MockMediaDevice { "239c24b3-2b15-11e3-8224-0800200c9a66"_s, "Mock video device 2"_s,
+            MockCameraProperties {
+                15,
+                RealtimeMediaSourceSettings::VideoFacingMode::Environment,
+                { 25.00, 22.50, 20.00, 17.50, 15.00, 12.50, 10.00, 7.50, 5.00 },
+                { { 1280, 720 }, { 960, 540 }, { 640, 480 }, { 352, 288 }, { 320, 240 }, { 160, 120 } },
+                Color::darkGray,
+            } },
+
+        MockMediaDevice { "SCREEN-1"_s, "Mock screen device 1"_s, MockDisplayProperties { 30, Color::lightGray } },
+        MockMediaDevice { "SCREEN-2"_s, "Mock screen device 2"_s, MockDisplayProperties { 10, Color::yellow } }
+    };
+}
+
+static Vector<MockMediaDevice>& devices()
+{
+    static auto devices = makeNeverDestroyed([] {
+        return defaultDevices();
+    }());
+    return devices;
+}
+
+static HashMap<String, MockMediaDevice>& deviceMap()
+{
+    static auto map = makeNeverDestroyed([] {
+        HashMap<String, MockMediaDevice> map;
+        for (auto& device : devices())
+            map.add(device.persistentId, device);
+
+        return map;
+    }());
+    return map;
+}
+
+static inline Vector<CaptureDevice>& deviceListForDevice(const MockMediaDevice& device)
+{
+    if (device.isMicrophone())
+        return MockRealtimeMediaSourceCenter::audioDevices();
+    if (device.isCamera())
+        return MockRealtimeMediaSourceCenter::videoDevices();
+
+    ASSERT(device.isDisplay());
+    return MockRealtimeMediaSourceCenter::displayDevices();
+}
+
 MockRealtimeMediaSourceCenter& MockRealtimeMediaSourceCenter::singleton()
 {
     static NeverDestroyed<MockRealtimeMediaSourceCenter> center;
@@ -52,19 +118,129 @@ void MockRealtimeMediaSourceCenter::setMockRealtimeMediaSourceCenterEnabled(bool
     }
 }
 
+static void createCaptureDevice(const MockMediaDevice& device)
+{
+    deviceListForDevice(device).append(MockRealtimeMediaSourceCenter::captureDeviceWithPersistentID(device.type(), device.persistentId).value());
+}
+
+void MockRealtimeMediaSourceCenter::resetDevices()
+{
+    setDevices(defaultDevices());
+    RealtimeMediaSourceCenter::singleton().captureDevicesChanged();
+}
+
 void MockRealtimeMediaSourceCenter::setDevices(Vector<MockMediaDevice>&& newMockDevices)
 {
-    MockRealtimeMediaSource::setDevices(WTFMove(newMockDevices));
+    audioDevices().clear();
+    videoDevices().clear();
+    displayDevices().clear();
+
+    auto& mockDevices = devices();
+    mockDevices = WTFMove(newMockDevices);
+
+    auto& map = deviceMap();
+    map.clear();
+
+    for (const auto& device : mockDevices) {
+        map.add(device.persistentId, device);
+        createCaptureDevice(device);
+    }
+    RealtimeMediaSourceCenter::singleton().captureDevicesChanged();
 }
 
 void MockRealtimeMediaSourceCenter::addDevice(const MockMediaDevice& device)
 {
-    MockRealtimeMediaSource::addDevice(device);
+    devices().append(device);
+    deviceMap().set(device.persistentId, device);
+    createCaptureDevice(device);
+    RealtimeMediaSourceCenter::singleton().captureDevicesChanged();
 }
 
 void MockRealtimeMediaSourceCenter::removeDevice(const String& persistentId)
 {
-    MockRealtimeMediaSource::removeDevice(persistentId);
+    auto& map = deviceMap();
+    auto iterator = map.find(persistentId);
+    if (iterator == map.end())
+        return;
+
+    devices().removeFirstMatching([&persistentId](const auto& device) {
+        return device.persistentId == persistentId;
+    });
+
+    deviceListForDevice(iterator->value).removeFirstMatching([&persistentId](const auto& device) {
+        return device.persistentId() == persistentId;
+    });
+
+    map.remove(iterator);
+    RealtimeMediaSourceCenter::singleton().captureDevicesChanged();
+}
+
+std::optional<MockMediaDevice> MockRealtimeMediaSourceCenter::mockDeviceWithPersistentID(const String& id)
+{
+    ASSERT(!id.isEmpty());
+
+    auto& map = deviceMap();
+    auto iterator = map.find(id);
+    if (iterator == map.end())
+        return std::nullopt;
+
+    return iterator->value;
+}
+
+std::optional<CaptureDevice> MockRealtimeMediaSourceCenter::captureDeviceWithPersistentID(CaptureDevice::DeviceType type, const String& id)
+{
+    ASSERT(!id.isEmpty());
+
+    auto& map = deviceMap();
+    auto iterator = map.find(id);
+    if (iterator == map.end() || iterator->value.type() != type)
+        return std::nullopt;
+
+    CaptureDevice device { iterator->value.persistentId, type, iterator->value.label };
+    device.setEnabled(true);
+    return WTFMove(device);
+}
+
+Vector<CaptureDevice>& MockRealtimeMediaSourceCenter::audioDevices()
+{
+    static auto audioDevices = makeNeverDestroyed([] {
+        Vector<CaptureDevice> audioDevices;
+        for (const auto& device : devices()) {
+            if (device.type() == CaptureDevice::DeviceType::Microphone)
+                audioDevices.append(captureDeviceWithPersistentID(CaptureDevice::DeviceType::Microphone, device.persistentId).value());
+        }
+        return audioDevices;
+    }());
+
+    return audioDevices;
+}
+
+Vector<CaptureDevice>& MockRealtimeMediaSourceCenter::videoDevices()
+{
+    static auto videoDevices = makeNeverDestroyed([] {
+        Vector<CaptureDevice> videoDevices;
+        for (const auto& device : devices()) {
+            if (device.type() == CaptureDevice::DeviceType::Camera)
+                videoDevices.append(captureDeviceWithPersistentID(CaptureDevice::DeviceType::Camera, device.persistentId).value());
+        }
+        return videoDevices;
+    }());
+
+    return videoDevices;
+}
+
+Vector<CaptureDevice>& MockRealtimeMediaSourceCenter::displayDevices()
+{
+    static auto displayDevices = makeNeverDestroyed([] {
+        Vector<CaptureDevice> displayDevices;
+        for (const auto& device : devices()) {
+            if (device.type() == CaptureDevice::DeviceType::Screen)
+                displayDevices.append(captureDeviceWithPersistentID(CaptureDevice::DeviceType::Screen, device.persistentId).value());
+        }
+        return displayDevices;
+    }());
+
+    return displayDevices;
 }
 
 } // namespace WebCore
index be47a0e..50b73ff 100644 (file)
@@ -1,6 +1,6 @@
 /*
  * Copyright (C) 2013 Google Inc. All rights reserved.
- * Copyright (C) 2013-2107 Apple Inc.  All rights reserved.
+ * Copyright (C) 2013-2108 Apple Inc.  All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions
@@ -29,6 +29,7 @@
 #if ENABLE(MEDIA_STREAM)
 
 #include "CaptureDeviceManager.h"
+#include "MockMediaDevice.h"
 #include "MockRealtimeAudioSource.h"
 #include "MockRealtimeVideoSource.h"
 #include "RealtimeMediaSourceCenter.h"
@@ -42,10 +43,18 @@ public:
     WEBCORE_EXPORT static void setDevices(Vector<MockMediaDevice>&&);
     WEBCORE_EXPORT static void addDevice(const MockMediaDevice&);
     WEBCORE_EXPORT static void removeDevice(const String& persistentId);
+    WEBCORE_EXPORT static void resetDevices();
 
     static RealtimeMediaSource::VideoCaptureFactory& videoCaptureSourceFactory() { return MockRealtimeVideoSource::factory(); }
     static RealtimeMediaSource::AudioCaptureFactory& audioCaptureSourceFactory() { return MockRealtimeAudioSource::factory(); }
 
+    static Vector<CaptureDevice>& audioDevices();
+    static Vector<CaptureDevice>& videoDevices();
+    static Vector<CaptureDevice>& displayDevices();
+
+    static std::optional<MockMediaDevice> mockDeviceWithPersistentID(const String&);
+    static std::optional<CaptureDevice> captureDeviceWithPersistentID(CaptureDevice::DeviceType, const String&);
+
 private:
     MockRealtimeMediaSourceCenter() = default;
     friend NeverDestroyed<MockRealtimeMediaSourceCenter>;
@@ -59,22 +68,20 @@ private:
     CaptureDeviceManager& videoCaptureDeviceManager() final { return m_videoCaptureDeviceManager; }
     CaptureDeviceManager& displayCaptureDeviceManager() final { return m_displayCaptureDeviceManager; }
 
-    static std::optional<CaptureDevice> captureDeviceWithPersistentID(CaptureDevice::DeviceType, const String&);
-
     class MockAudioCaptureDeviceManager final : public CaptureDeviceManager {
     private:
-        const Vector<CaptureDevice>& captureDevices() final { return MockRealtimeMediaSource::audioDevices(); }
-        std::optional<CaptureDevice> captureDeviceWithPersistentID(CaptureDevice::DeviceType type, const String& id) final { return MockRealtimeMediaSource::captureDeviceWithPersistentID(type, id); }
+        const Vector<CaptureDevice>& captureDevices() final { return MockRealtimeMediaSourceCenter::audioDevices(); }
+        std::optional<CaptureDevice> captureDeviceWithPersistentID(CaptureDevice::DeviceType type, const String& id) final { return MockRealtimeMediaSourceCenter::captureDeviceWithPersistentID(type, id); }
     };
     class MockVideoCaptureDeviceManager final : public CaptureDeviceManager {
     private:
-        const Vector<CaptureDevice>& captureDevices() final { return MockRealtimeMediaSource::videoDevices(); }
-        std::optional<CaptureDevice> captureDeviceWithPersistentID(CaptureDevice::DeviceType type, const String& id) final { return MockRealtimeMediaSource::captureDeviceWithPersistentID(type, id); }
+        const Vector<CaptureDevice>& captureDevices() final { return MockRealtimeMediaSourceCenter::videoDevices(); }
+        std::optional<CaptureDevice> captureDeviceWithPersistentID(CaptureDevice::DeviceType type, const String& id) final { return MockRealtimeMediaSourceCenter::captureDeviceWithPersistentID(type, id); }
     };
     class MockDisplayCaptureDeviceManager final : public CaptureDeviceManager {
     private:
-        const Vector<CaptureDevice>& captureDevices() final { return MockRealtimeMediaSource::displayDevices(); }
-        std::optional<CaptureDevice> captureDeviceWithPersistentID(CaptureDevice::DeviceType type, const String& id) final { return MockRealtimeMediaSource::captureDeviceWithPersistentID(type, id); }
+        const Vector<CaptureDevice>& captureDevices() final { return MockRealtimeMediaSourceCenter::displayDevices(); }
+        std::optional<CaptureDevice> captureDeviceWithPersistentID(CaptureDevice::DeviceType type, const String& id) final { return MockRealtimeMediaSourceCenter::captureDeviceWithPersistentID(type, id); }
     };
 
     MockAudioCaptureDeviceManager m_audioCaptureDeviceManager;
index 9c41e1c..1eec441 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2015-2017 Apple Inc. All rights reserved.
+ * Copyright (C) 2015-2018 Apple Inc. All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions
@@ -53,7 +53,7 @@ class MockRealtimeVideoSourceFactory : public RealtimeMediaSource::VideoCaptureF
 public:
     CaptureSourceOrError createVideoCaptureSource(const CaptureDevice& device, const MediaConstraints* constraints) final
     {
-        ASSERT(MockRealtimeMediaSource::captureDeviceWithPersistentID(device.type(), device.persistentId()));
+        ASSERT(MockRealtimeMediaSourceCenter::captureDeviceWithPersistentID(device.type(), device.persistentId()));
 
         switch (device.type()) {
         case CaptureDevice::DeviceType::Camera:
@@ -85,7 +85,12 @@ private:
 #if !PLATFORM(MAC) && !PLATFORM(IOS) && !(USE(GSTREAMER) && USE(LIBWEBRTC))
 CaptureSourceOrError MockRealtimeVideoSource::create(const String& deviceID, const String& name, const MediaConstraints* constraints)
 {
-    auto source = adoptRef(*new MockRealtimeVideoSource(deviceID, name));
+    auto device = MockRealtimeMediaSourceCenter::mockDeviceWithPersistentID(deviceID);
+    ASSERT(device);
+    if (!device)
+        return { };
+
+    auto source = adoptRef(*new MockRealtimeVideoSource(WTFMove(device), deviceID, name));
     if (constraints && source->applyConstraints(*constraints))
         return { };
 
@@ -105,62 +110,59 @@ RealtimeMediaSource::VideoCaptureFactory& MockRealtimeVideoSource::factory()
 }
 
 MockRealtimeVideoSource::MockRealtimeVideoSource(const String& deviceID, const String& name)
-    : MockRealtimeMediaSource(deviceID, RealtimeMediaSource::Type::Video, name)
-    , m_timer(RunLoop::current(), this, &MockRealtimeVideoSource::generateFrame)
+    : RealtimeVideoSource(deviceID, name)
+    , m_emitFrameTimer(RunLoop::current(), this, &MockRealtimeVideoSource::generateFrame)
 {
+    auto device = MockRealtimeMediaSourceCenter::mockDeviceWithPersistentID(deviceID);
+    ASSERT(device);
+    m_device = *device;
+
     m_dashWidths.reserveInitialCapacity(2);
     m_dashWidths.uncheckedAppend(6);
     m_dashWidths.uncheckedAppend(6);
 
     if (mockScreen()) {
-        setFrameRate(WTF::get<MockDisplayProperties>(device().properties).defaultFrameRate);
+        auto& properties = WTF::get<MockDisplayProperties>(m_device.properties);
+        setFrameRate(properties.defaultFrameRate);
+        m_fillColor = properties.fillColor;
         return;
     }
 
-    auto& properties = WTF::get<MockCameraProperties>(device().properties);
-    setFrameRate(properties.defaultFrameRate);
-    setFacingMode(properties.facingModeCapability);
+    auto& properties = WTF::get<MockCameraProperties>(m_device.properties);
+    setFrameRate(properties.frameRates[0]);
+    setFacingMode(properties.facingMode);
+    setSupportedFrameRates(WTFMove(properties.frameRates));
+    setSupportedCaptureSizes(WTFMove(properties.frameSizes));
+    m_fillColor = properties.fillColor;
 }
 
-MockRealtimeVideoSource::~MockRealtimeVideoSource()
-{
-#if PLATFORM(IOS)
-    MockRealtimeMediaSourceCenter::videoCaptureSourceFactory().unsetActiveSource(*this);
-#endif
-}
-
-void MockRealtimeVideoSource::startProducingData()
+const RealtimeMediaSourceCapabilities& MockRealtimeVideoSource::capabilities() const
 {
-#if PLATFORM(IOS)
-    MockRealtimeMediaSourceCenter::videoCaptureSourceFactory().setActiveSource(*this);
-#endif
+    if (!m_capabilities) {
+        RealtimeMediaSourceCapabilities capabilities(settings().supportedConstraints());
+
+        capabilities.setDeviceId(id());
+        if (mockCamera()) {
+            capabilities.addFacingMode(WTF::get<MockCameraProperties>(m_device.properties).facingMode);
+            addSupportedCapabilities(capabilities);
+        } else {
+            capabilities.setWidth(CapabilityValueOrRange(72, 2880));
+            capabilities.setHeight(CapabilityValueOrRange(45, 1800));
+            capabilities.setFrameRate(CapabilityValueOrRange(.01, 60.0));
+        }
 
-    if (size().isEmpty()) {
-        setWidth(640);
-        setHeight(480);
+        m_capabilities = WTFMove(capabilities);
     }
-
-    m_startTime = MonotonicTime::now();
-    m_timer.startRepeating(1_ms * lround(1000 / frameRate()));
-}
-
-void MockRealtimeVideoSource::stopProducingData()
-{
-    m_timer.stop();
-    m_elapsedTime += MonotonicTime::now() - m_startTime;
-    m_startTime = MonotonicTime::nan();
+    return m_capabilities.value();
 }
 
-Seconds MockRealtimeVideoSource::elapsedTime()
+const RealtimeMediaSourceSettings& MockRealtimeVideoSource::settings() const
 {
-    if (std::isnan(m_startTime))
-        return m_elapsedTime;
+    if (m_currentSettings)
+        return m_currentSettings.value();
 
-    return m_elapsedTime + (MonotonicTime::now() - m_startTime);
-}
 
-void MockRealtimeVideoSource::updateSettings(RealtimeMediaSourceSettings& settings)
-{
+    RealtimeMediaSourceSettings settings;
     if (mockCamera())
         settings.setFacingMode(facingMode());
     else {
@@ -173,49 +175,66 @@ void MockRealtimeVideoSource::updateSettings(RealtimeMediaSourceSettings& settin
     settings.setHeight(size.height());
     if (aspectRatio())
         settings.setAspectRatio(aspectRatio());
+    settings.setDeviceId(id());
+
+    RealtimeMediaSourceSupportedConstraints supportedConstraints;
+    supportedConstraints.setSupportsDeviceId(true);
+    supportedConstraints.setSupportsFrameRate(true);
+    supportedConstraints.setSupportsWidth(true);
+    supportedConstraints.setSupportsHeight(true);
+    supportedConstraints.setSupportsAspectRatio(true);
+    if (mockCamera())
+        supportedConstraints.setSupportsFacingMode(true);
+    settings.setSupportedConstraints(supportedConstraints);
+
+    m_currentSettings = WTFMove(settings);
+
+    return m_currentSettings.value();
 }
 
-void MockRealtimeVideoSource::initializeCapabilities(RealtimeMediaSourceCapabilities& capabilities)
+void MockRealtimeVideoSource::settingsDidChange()
 {
-    if (mockCamera()) {
-        capabilities.addFacingMode(WTF::get<MockCameraProperties>(device().properties).facingModeCapability);
+    m_currentSettings = std::nullopt;
+    RealtimeVideoSource::settingsDidChange();
+}
 
-        capabilities.setWidth(CapabilityValueOrRange(320, 1920));
-        capabilities.setHeight(CapabilityValueOrRange(240, 1080));
-        capabilities.setFrameRate(CapabilityValueOrRange(15.0, 60.0));
-        capabilities.setAspectRatio(CapabilityValueOrRange(4 / 3.0, 16 / 9.0));
-    } else {
-        capabilities.setWidth(CapabilityValueOrRange(72, 2880));
-        capabilities.setHeight(CapabilityValueOrRange(45, 1800));
-        capabilities.setFrameRate(CapabilityValueOrRange(.01, 60.0));
-    }
+void MockRealtimeVideoSource::startCaptureTimer()
+{
+    m_emitFrameTimer.startRepeating(1_s / frameRate());
 }
 
-void MockRealtimeVideoSource::initializeSupportedConstraints(RealtimeMediaSourceSupportedConstraints& supportedConstraints)
+void MockRealtimeVideoSource::startProducingData()
 {
-    supportedConstraints.setSupportsWidth(true);
-    supportedConstraints.setSupportsHeight(true);
-    supportedConstraints.setSupportsAspectRatio(true);
-    supportedConstraints.setSupportsFrameRate(true);
-    if (mockCamera())
-        supportedConstraints.setSupportsFacingMode(true);
+    prepareToProduceData();
+    startCaptureTimer();
+    m_startTime = MonotonicTime::now();
 }
 
-bool MockRealtimeVideoSource::applyFrameRate(double rate)
+void MockRealtimeVideoSource::stopProducingData()
 {
-    if (m_timer.isActive())
-        m_timer.startRepeating(1_ms * lround(1000 / rate));
+    m_emitFrameTimer.stop();
+    m_elapsedTime += MonotonicTime::now() - m_startTime;
+    m_startTime = MonotonicTime::nan();
+}
 
-    updateSampleBuffer();
-    return true;
+Seconds MockRealtimeVideoSource::elapsedTime()
+{
+    if (std::isnan(m_startTime))
+        return m_elapsedTime;
+
+    return m_elapsedTime + (MonotonicTime::now() - m_startTime);
 }
 
 bool MockRealtimeVideoSource::applySize(const IntSize& size)
 {
+    if (!RealtimeVideoSource::applySize(size))
+        return false;
+
     m_baseFontSize = size.height() * .08;
     m_bipBopFontSize = m_baseFontSize * 2.5;
     m_statsFontSize = m_baseFontSize * .5;
     m_imageBuffer = nullptr;
+
     return true;
 }
 
@@ -344,12 +363,16 @@ void MockRealtimeVideoSource::drawText(GraphicsContext& context)
     timeLocation.move(0, m_baseFontSize);
     context.drawText(timeFont, TextRun((StringView(string))), timeLocation);
 
-    FloatPoint statsLocation(size.width() * .65, size.height() * .75);
-    string = String::format("Frame rate: %ffps", frameRate());
+    FloatPoint statsLocation(size.width() * .45, size.height() * .75);
+    string = String::format("Requested frame rate: %.1f fps", frameRate());
     context.drawText(statsFont, TextRun((StringView(string))), statsLocation);
 
-    string = String::format("Size: %u x %u", size.width(), size.height());
     statsLocation.move(0, m_statsFontSize);
+    string = String::format("Observed frame rate: %.1f fps", observedFrameRate());
+    context.drawText(statsFont, TextRun((StringView(string))), statsLocation);
+
+    statsLocation.move(0, m_statsFontSize);
+    string = String::format("Size: %u x %u", size.width(), size.height());
     context.drawText(statsFont, TextRun((StringView(string))), statsLocation);
 
     if (mockCamera()) {
@@ -415,8 +438,7 @@ void MockRealtimeVideoSource::generateFrame()
     auto& size = this->size();
     FloatRect frameRect(FloatPoint(), size);
 
-    auto fillColor = mockCamera() ? WTF::get<MockCameraProperties>(device().properties).fillColor : WTF::get<MockDisplayProperties>(device().properties).fillColor;
-    context.fillRect(FloatRect(FloatPoint(), size), fillColor);
+    context.fillRect(FloatRect(FloatPoint(), size), m_fillColor);
 
     if (!muted()) {
         drawText(context);
index a6589b8..6ac7358 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2015-2017 Apple Inc. All rights reserved.
+ * Copyright (C) 2015-2018 Apple Inc. All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions
@@ -35,7 +35,8 @@
 
 #include "FontCascade.h"
 #include "ImageBuffer.h"
-#include "MockRealtimeMediaSource.h"
+#include "MockMediaDevice.h"
+#include "RealtimeVideoSource.h"
 #include <wtf/RunLoop.h>
 
 namespace WebCore {
@@ -43,28 +44,28 @@ namespace WebCore {
 class FloatRect;
 class GraphicsContext;
 
-class MockRealtimeVideoSource : public MockRealtimeMediaSource {
+class MockRealtimeVideoSource : public RealtimeVideoSource {
 public:
 
     static CaptureSourceOrError create(const String& deviceID, const String& name, const MediaConstraints*);
 
     static VideoCaptureFactory& factory();
 
-    virtual ~MockRealtimeVideoSource();
-
 protected:
     MockRealtimeVideoSource(const String& deviceID, const String& name);
-    virtual void updateSampleBuffer() { }
 
+    virtual void updateSampleBuffer() = 0;
+
+    void setCurrentFrame(MediaSample&);
     ImageBuffer* imageBuffer() const;
 
     Seconds elapsedTime();
     bool applySize(const IntSize&) override;
 
 private:
-    void updateSettings(RealtimeMediaSourceSettings&) override;
-    void initializeCapabilities(RealtimeMediaSourceCapabilities&) override;
-    void initializeSupportedConstraints(RealtimeMediaSourceSupportedConstraints&) override;
+    const RealtimeMediaSourceCapabilities& capabilities() const final;
+    const RealtimeMediaSourceSettings& settings() const final;
+    void settingsDidChange() final;
 
     void startProducingData() final;
     void stopProducingData() final;
@@ -73,18 +74,18 @@ private:
     void drawText(GraphicsContext&);
     void drawBoxes(GraphicsContext&);
 
-    bool applyFrameRate(double) override;
     bool applyFacingMode(RealtimeMediaSourceSettings::VideoFacingMode) override { return true; }
     bool applyAspectRatio(double) override { return true; }
 
     bool isCaptureSource() const final { return true; }
 
     void generateFrame();
+    void startCaptureTimer();
 
     void delaySamples(Seconds) override;
 
-    bool mockCamera() const { return WTF::holds_alternative<MockCameraProperties>(device().properties); }
-    bool mockScreen() const { return WTF::holds_alternative<MockDisplayProperties>(device().properties); }
+    bool mockCamera() const { return WTF::holds_alternative<MockCameraProperties>(m_device.properties); }
+    bool mockScreen() const { return WTF::holds_alternative<MockDisplayProperties>(m_device.properties); }
 
     float m_baseFontSize { 0 };
     float m_bipBopFontSize { 0 };
@@ -100,8 +101,12 @@ private:
     MonotonicTime m_delayUntil;
 
     unsigned m_frameNumber { 0 };
-
-    RunLoop::Timer<MockRealtimeVideoSource> m_timer;
+    RunLoop::Timer<MockRealtimeVideoSource> m_emitFrameTimer;
+    mutable std::optional<RealtimeMediaSourceCapabilities> m_capabilities;
+    mutable std::optional<RealtimeMediaSourceSettings> m_currentSettings;
+    RealtimeMediaSourceSupportedConstraints m_supportedConstraints;
+    Color m_fillColor { Color::black };
+    MockMediaDevice m_device;
 };
 
 } // namespace WebCore
index 8c0762c..9688a9a 100644 (file)
@@ -1,3 +1,16 @@
+2018-08-30  Eric Carlson  <eric.carlson@apple.com>
+
+        Mock video devices should only support discrete sizes
+        https://bugs.webkit.org/show_bug.cgi?id=189000
+        <rdar://problem/43766551>
+
+        Reviewed by Youenn Fablet.
+
+        * UIProcess/WebProcessPool.cpp:
+        (WebKit::WebProcessPool::resetMockMediaDevices):
+        * WebProcess/WebProcess.cpp:
+        (WebKit::WebProcess::resetMockMediaDevices):
+
 2018-08-30  Olivia Barnett  <obarnett@apple.com>
 
         Web Share API compatible with AppleTV and WatchOS
index 88f6552..a641578 100644 (file)
@@ -2280,7 +2280,7 @@ void WebProcessPool::removeMockMediaDevice(const String& persistentId)
 void WebProcessPool::resetMockMediaDevices()
 {
 #if ENABLE(MEDIA_STREAM)
-    MockRealtimeMediaSource::resetDevices();
+    MockRealtimeMediaSourceCenter::resetDevices();
     sendToAllProcesses(Messages::WebProcess::ResetMockMediaDevices { });
 #endif
 }
index 0c1aeb6..8840942 100644 (file)
@@ -1745,7 +1745,7 @@ void WebProcess::removeMockMediaDevice(const String& persistentId)
 
 void WebProcess::resetMockMediaDevices()
 {
-    MockRealtimeMediaSource::resetDevices();
+    MockRealtimeMediaSourceCenter::resetDevices();
 }
 #endif