[MediaStream] Update constraints supported by getDisplayMedia
authoreric.carlson@apple.com <eric.carlson@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Tue, 25 Sep 2018 18:37:29 +0000 (18:37 +0000)
committereric.carlson@apple.com <eric.carlson@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Tue, 25 Sep 2018 18:37:29 +0000 (18:37 +0000)
https://bugs.webkit.org/show_bug.cgi?id=189930

Reviewed by Youenn Fablet.

Source/WebCore:

No new tests, updated http/tests/media/media-stream/get-display-media-prompt.html.

* Modules/mediastream/MediaDevices.cpp:
(WebCore::MediaDevices::getDisplayMedia const): Ignore audio constraints.

* Modules/mediastream/UserMediaRequest.cpp:
(WebCore::hasInvalidGetDisplayMediaConstraint): Check for invalid constraints.
(WebCore::UserMediaRequest::start): Check for invalid constraints.
(WebCore::UserMediaRequest::deny): Support new error.
* Modules/mediastream/UserMediaRequest.h:

* platform/mediastream/RealtimeMediaSourceCenter.cpp:
(WebCore::RealtimeMediaSourceCenter::validateRequestConstraints):

LayoutTests:

* http/tests/media/media-stream/get-display-media-prompt-expected.txt:
* http/tests/media/media-stream/get-display-media-prompt.html:

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

LayoutTests/ChangeLog
LayoutTests/http/tests/media/media-stream/get-display-media-prompt-expected.txt
LayoutTests/http/tests/media/media-stream/get-display-media-prompt.html
Source/WebCore/ChangeLog
Source/WebCore/Modules/mediastream/MediaDevices.cpp
Source/WebCore/Modules/mediastream/UserMediaRequest.cpp
Source/WebCore/Modules/mediastream/UserMediaRequest.h
Source/WebCore/platform/mediastream/RealtimeMediaSourceCenter.cpp
Source/WebCore/platform/mediastream/RealtimeMediaSourceCenter.h

index a290208..244c3c8 100644 (file)
@@ -1,3 +1,13 @@
+2018-09-25  Eric Carlson  <eric.carlson@apple.com>
+
+        [MediaStream] Update constraints supported by getDisplayMedia
+        https://bugs.webkit.org/show_bug.cgi?id=189930
+
+        Reviewed by Youenn Fablet.
+
+        * http/tests/media/media-stream/get-display-media-prompt-expected.txt:
+        * http/tests/media/media-stream/get-display-media-prompt.html:
+
 2018-09-25  Ryan Haddad  <ryanhaddad@apple.com>
 
         [resource-timing] imported/w3c/web-platform-tests/resource-timing/resource_timing.worker.html times out on WK1
index 878a4fc..fae8690 100644 (file)
@@ -5,26 +5,49 @@ On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE
 
 PASS numberOfTimesGetUserMediaPromptHasBeenCalled() is 0
 
-** Request an audio-only stream, the user should be prompted **
-PASS numberOfTimesGetUserMediaPromptHasBeenCalled() is 1
-PASS stream.getAudioTracks().length is 1
-PASS stream.getVideoTracks().length is 0
+** Request an audio-only stream, the user should not be prompted **
+PASS numberOfTimesGetUserMediaPromptHasBeenCalled() is 0
+PASS stream is undefined.
+PASS err instanceof Error  is true
+PASS err.name is "TypeError"
 
 ** Request an video-only stream, the user should be prompted **
+PASS numberOfTimesGetUserMediaPromptHasBeenCalled() is 1
+PASS stream.getAudioTracks().length is 0
+PASS stream.getVideoTracks().length is 1
+
+** Request a stream with audio and video, the user should be prompted but no audio track should be created **
 PASS numberOfTimesGetUserMediaPromptHasBeenCalled() is 2
 PASS stream.getAudioTracks().length is 0
 PASS stream.getVideoTracks().length is 1
 
-** Request a stream with audio and video, the user should be prompted **
+** Request a stream with 'max' constraints, the user should not be prompted **
+PASS numberOfTimesGetUserMediaPromptHasBeenCalled() is 2
+PASS stream is undefined.
+PASS err instanceof Error  is true
+PASS err.name is "TypeError"
+
+** Request a stream with 'min' constraints, the user should not be prompted **
+PASS numberOfTimesGetUserMediaPromptHasBeenCalled() is 2
+PASS stream is undefined.
+PASS err instanceof Error  is true
+PASS err.name is "TypeError"
+
+** Request a stream with 'advanced' constraints, the user should not be prompted **
+PASS numberOfTimesGetUserMediaPromptHasBeenCalled() is 2
+PASS stream is undefined.
+PASS err instanceof Error  is true
+PASS err.name is "TypeError"
+
+** Request a stream with valid constraints, the user should be prompted **
 PASS numberOfTimesGetUserMediaPromptHasBeenCalled() is 3
-PASS stream.getAudioTracks().length is 1
+PASS stream.getAudioTracks().length is 0
 PASS stream.getVideoTracks().length is 1
 
-** Request a stream with invalid constraints, the user should not be prompted **
-PASS numberOfTimesGetUserMediaPromptHasBeenCalled() is 3
-PASS stream is null
-PASS err instanceof Error  is true
-PASS err.name is "InvalidAccessError"
+** Request a stream with an exact audio constraint, it should be ignored **
+PASS numberOfTimesGetUserMediaPromptHasBeenCalled() is 4
+PASS stream.getAudioTracks().length is 0
+PASS stream.getVideoTracks().length is 1
 
 PASS successfullyParsed is true
 
index b445821..fd739e6 100644 (file)
     }
     
     async function promptForAudioOnly() {
-        debug("<br>** Request an audio-only stream, the user should be prompted **");
-        stream = await navigator.mediaDevices.getDisplayMedia({ audio: true });
-        shouldBe("numberOfTimesGetUserMediaPromptHasBeenCalled()", "1");
-        shouldBe("stream.getAudioTracks().length", "1");
-        shouldBe("stream.getVideoTracks().length", "0");
+        debug("<br>** Request an audio-only stream, the user should not be prompted **");
+        stream = await navigator.mediaDevices.getDisplayMedia({ audio: true })
+            .catch((e) => { err = e; });
+        shouldBe("numberOfTimesGetUserMediaPromptHasBeenCalled()", "0");
+        shouldBeUndefined("stream");
+        shouldBeTrue("err instanceof Error ");
+        shouldBeEqualToString("err.name", "TypeError");
     }
 
     async function promptForVideoOnly() {
         debug("<br>** Request an video-only stream, the user should be prompted **");
         stream = await navigator.mediaDevices.getDisplayMedia({ video: true });
-        shouldBe("numberOfTimesGetUserMediaPromptHasBeenCalled()", "2");
+        shouldBe("numberOfTimesGetUserMediaPromptHasBeenCalled()", "1");
         shouldBe("stream.getAudioTracks().length", "0");
         shouldBe("stream.getVideoTracks().length", "1");
     }
 
     async function promptForAudioAndVideo() {
-        debug("<br>** Request a stream with audio and video, the user should be prompted **");
+        debug("<br>** Request a stream with audio and video, the user should be prompted but no audio track should be created **");
         stream = await navigator.mediaDevices.getDisplayMedia({ video: true, audio: true });
-        shouldBe("numberOfTimesGetUserMediaPromptHasBeenCalled()", "3");
-        shouldBe("stream.getAudioTracks().length", "1");
+        shouldBe("numberOfTimesGetUserMediaPromptHasBeenCalled()", "2");
+        shouldBe("stream.getAudioTracks().length", "0");
         shouldBe("stream.getVideoTracks().length", "1");
     }
     
-    async function promptWithMediaTrackConstraints() {
-        debug("<br>** Request a stream with invalid constraints, the user should not be prompted **");
+    async function promptWithExactVideoConstraints() {
+        debug("<br>** Request a stream with 'max' constraints, the user should not be prompted **");
+
+        stream = null;
+        stream = await navigator.mediaDevices.getDisplayMedia({ video: {width: {exact: 640}, height: {exact: 480}} })
+            .catch((e) => { err = e; });
+        
+        shouldBe("numberOfTimesGetUserMediaPromptHasBeenCalled()", "2");
+        shouldBeUndefined("stream");
+        shouldBeTrue("err instanceof Error ");
+        shouldBeEqualToString("err.name", "TypeError");
+    }
+
+    async function promptWithMinVideoConstraints() {
+        debug("<br>** Request a stream with 'min' constraints, the user should not be prompted **");
+
+        stream = null;
+        stream = await navigator.mediaDevices.getDisplayMedia({ video: {width: {min: 640}, height: {min: 480}} })
+            .catch((e) => { err = e; });
+        shouldBe("numberOfTimesGetUserMediaPromptHasBeenCalled()", "2");
+        shouldBeUndefined("stream");
+        shouldBeTrue("err instanceof Error ");
+        shouldBeEqualToString("err.name", "TypeError");
+    }
+
+    async function promptWithAdvancedVideoConstraints() {
+        debug("<br>** Request a stream with 'advanced' constraints, the user should not be prompted **");
+
+        stream = null;
+        stream = await navigator.mediaDevices.getDisplayMedia({ video: { width: 640, height: 480, advanced: [ { width: 1920, height: 1280 } ] } })
+            .catch((e) => { err = e; });
+        shouldBe("numberOfTimesGetUserMediaPromptHasBeenCalled()", "2");
+        shouldBeUndefined("stream");
+        shouldBeTrue("err instanceof Error ");
+        shouldBeEqualToString("err.name", "TypeError");
+    }
+
+    async function promptWithValidVideoConstraints() {
+        debug("<br>** Request a stream with valid constraints, the user should be prompted **");
+
         stream = null;
-        try {
-            stream = await navigator.mediaDevices.getDisplayMedia({ video: {width: {exact: 640}, height: {exact: 480}} });
-        } catch (e) {
-            err = e;
-        }
+        stream = await navigator.mediaDevices.getDisplayMedia({ video: {width: 640, height: 480} })
+            .catch((e) => { err = e; });
         
         shouldBe("numberOfTimesGetUserMediaPromptHasBeenCalled()", "3");
-        shouldBeNull("stream");
-        shouldBeTrue("err instanceof Error "); 
-        shouldBeEqualToString("err.name", "InvalidAccessError");
+        shouldBe("stream.getAudioTracks().length", "0");
+        shouldBe("stream.getVideoTracks().length", "1");
     }
 
+    async function promptWithInvalidAudioConstraint() {
+        debug("<br>** Request a stream with an exact audio constraint, it should be ignored **");
+
+        stream = null;
+        stream = await navigator.mediaDevices.getDisplayMedia({ video: true, audio: { volume: { exact: 0.5 } } });
+        shouldBe("numberOfTimesGetUserMediaPromptHasBeenCalled()", "4");
+        shouldBe("stream.getAudioTracks().length", "0");
+        shouldBe("stream.getVideoTracks().length", "1");
+    }
+    
     (async function() {
         description('Test basic getDisplayMedia prompting behavior');
         jsTestIsAsync = true;
         await promptForAudioOnly();
         await promptForVideoOnly();
         await promptForAudioAndVideo();
-        await promptWithMediaTrackConstraints();
+        await promptWithExactVideoConstraints();
+        await promptWithMinVideoConstraints();
+        await promptWithAdvancedVideoConstraints();
+        await promptWithValidVideoConstraints();
+        await promptWithInvalidAudioConstraint();
 
         debug("");
         finishJSTest();
index 1de906b..afd43ad 100644 (file)
@@ -1,3 +1,24 @@
+2018-09-25  Eric Carlson  <eric.carlson@apple.com>
+
+        [MediaStream] Update constraints supported by getDisplayMedia
+        https://bugs.webkit.org/show_bug.cgi?id=189930
+
+        Reviewed by Youenn Fablet.
+
+        No new tests, updated http/tests/media/media-stream/get-display-media-prompt.html.
+
+        * Modules/mediastream/MediaDevices.cpp:
+        (WebCore::MediaDevices::getDisplayMedia const): Ignore audio constraints.
+
+        * Modules/mediastream/UserMediaRequest.cpp:
+        (WebCore::hasInvalidGetDisplayMediaConstraint): Check for invalid constraints.
+        (WebCore::UserMediaRequest::start): Check for invalid constraints.
+        (WebCore::UserMediaRequest::deny): Support new error.
+        * Modules/mediastream/UserMediaRequest.h:
+
+        * platform/mediastream/RealtimeMediaSourceCenter.cpp:
+        (WebCore::RealtimeMediaSourceCenter::validateRequestConstraints):
+
 2018-09-25  Xabier Rodriguez Calvar  <calvaris@igalia.com>
 
         [EME] Fix variable name that should have gone in r236317
index d9b0bb7..690ff36 100644 (file)
@@ -120,7 +120,7 @@ ExceptionOr<void> MediaDevices::getDisplayMedia(const StreamConstraints& constra
     if (!document)
         return Exception { InvalidStateError };
 
-    auto request = UserMediaRequest::create(*document, { MediaStreamRequest::Type::DisplayMedia, createMediaConstraints(constraints.audio), createMediaConstraints(constraints.video) }, WTFMove(promise));
+    auto request = UserMediaRequest::create(*document, { MediaStreamRequest::Type::DisplayMedia, { }, createMediaConstraints(constraints.video) }, WTFMove(promise));
     if (request)
         request->start();
 
index da5c108..125d6d1 100644 (file)
@@ -156,6 +156,74 @@ static bool canCallGetUserMedia(Document& document, bool wantsAudio, bool wantsV
     return true;
 }
 
+static bool hasInvalidGetDisplayMediaConstraint(const MediaConstraints& constraints)
+{
+    // https://w3c.github.io/mediacapture-screen-share/#navigator-additions
+    // 1. Let constraints be the method's first argument.
+    // 2. For each member present in constraints whose value, value, is a dictionary, run the following steps:
+    //     1. If value contains a member named advanced, return a promise rejected with a newly created TypeError.
+    //     2. If value contains a member which in turn is a dictionary containing a member named either min or
+    //        exact, return a promise rejected with a newly created TypeError.
+    if (!constraints.isValid)
+        return false;
+
+    if (!constraints.advancedConstraints.isEmpty())
+        return true;
+
+    bool invalid = false;
+    constraints.mandatoryConstraints.filter([&invalid] (const MediaConstraint& constraint) mutable {
+        switch (constraint.constraintType()) {
+        case MediaConstraintType::Width:
+        case MediaConstraintType::Height: {
+            auto& intConstraint = downcast<IntConstraint>(constraint);
+            int value;
+            invalid = intConstraint.getExact(value) || intConstraint.getMin(value);
+            break;
+        }
+
+        case MediaConstraintType::AspectRatio:
+        case MediaConstraintType::FrameRate: {
+            auto& doubleConstraint = downcast<DoubleConstraint>(constraint);
+            double value;
+            invalid = doubleConstraint.getExact(value) || doubleConstraint.getMin(value);
+            break;
+        }
+
+        case MediaConstraintType::DisplaySurface:
+        case MediaConstraintType::LogicalSurface: {
+            auto& boolConstraint = downcast<BooleanConstraint>(constraint);
+            bool value;
+            invalid = boolConstraint.getExact(value);
+            break;
+        }
+
+        case MediaConstraintType::FacingMode:
+        case MediaConstraintType::DeviceId:
+        case MediaConstraintType::GroupId: {
+            auto& stringConstraint = downcast<StringConstraint>(constraint);
+            Vector<String> values;
+            invalid = stringConstraint.getExact(values);
+            break;
+        }
+
+        case MediaConstraintType::SampleRate:
+        case MediaConstraintType::SampleSize:
+        case MediaConstraintType::Volume:
+        case MediaConstraintType::EchoCancellation:
+            // Ignored.
+            break;
+
+        case MediaConstraintType::Unknown:
+            ASSERT_NOT_REACHED();
+            break;
+        }
+
+        return invalid;
+    });
+
+    return invalid;
+}
+
 void UserMediaRequest::start()
 {
     ASSERT(m_scriptExecutionContext);
@@ -165,19 +233,8 @@ void UserMediaRequest::start()
     }
 
     if (m_request.type == MediaStreamRequest::Type::DisplayMedia) {
-        // https://w3c.github.io/mediacapture-screen-share/#constraints
-        // 5.2 Constraining Display Surface Selection
-        // The getDisplayMedia function does not permit the use of constraints for selection of a source as described
-        // in the getUserMedia() algorithm. Prior to invoking the getUserMedia() algorithm, if either of the video
-        // and audio attributes are set to a MediaTrackConstraints value (as opposed to being absent or set to a
-        // Boolean value), reject the promise with a InvalidAccessError and abort.
-        if (m_request.videoConstraints.isValid && !(m_request.videoConstraints.mandatoryConstraints.isEmpty() && m_request.videoConstraints.advancedConstraints.isEmpty())) {
-            deny(MediaAccessDenialReason::InvalidAccess);
-            return;
-        }
-
-        if (m_request.audioConstraints.isValid && !(m_request.audioConstraints.mandatoryConstraints.isEmpty() && m_request.audioConstraints.advancedConstraints.isEmpty())) {
-            deny(MediaAccessDenialReason::InvalidAccess);
+        if (hasInvalidGetDisplayMediaConstraint(m_request.videoConstraints)) {
+            deny(MediaAccessDenialReason::IllegalConstraint);
             return;
         }
     }
@@ -265,6 +322,10 @@ void UserMediaRequest::deny(MediaAccessDenialReason reason, const String& messag
 
     ExceptionCode code;
     switch (reason) {
+    case MediaAccessDenialReason::IllegalConstraint:
+        RELEASE_LOG(MediaStream, "UserMediaRequest::deny - invalid constraints");
+        code = TypeError;
+        break;
     case MediaAccessDenialReason::NoConstraints:
         RELEASE_LOG(MediaStream, "UserMediaRequest::deny - no constraints");
         code = TypeError;
index c9e9d20..de51fd9 100644 (file)
@@ -56,7 +56,7 @@ public:
     WEBCORE_EXPORT void setAllowedMediaDeviceUIDs(const String& audioDeviceUID, const String& videoDeviceUID);
     WEBCORE_EXPORT void allow(CaptureDevice&& audioDevice, CaptureDevice&& videoDevice, String&& deviceIdentifierHashSalt);
 
-    enum MediaAccessDenialReason { NoConstraints, UserMediaDisabled, NoCaptureDevices, InvalidConstraint, HardwareError, PermissionDenied, InvalidAccess, OtherFailure };
+    enum MediaAccessDenialReason { NoConstraints, UserMediaDisabled, NoCaptureDevices, InvalidConstraint, HardwareError, PermissionDenied, InvalidAccess, IllegalConstraint, OtherFailure };
     WEBCORE_EXPORT void deny(MediaAccessDenialReason, const String& errorMessage = emptyString());
 
     const Vector<String>& audioDeviceUIDs() const { return m_audioDeviceUIDs; }
index ffd51d4..77dee4e 100644 (file)
@@ -207,71 +207,74 @@ void RealtimeMediaSourceCenter::captureDevicesChanged()
         m_deviceChangedObserver();
 }
 
-void RealtimeMediaSourceCenter::validateRequestConstraints(ValidConstraintsHandler&& validHandler, InvalidConstraintsHandler&& invalidHandler, const MediaStreamRequest& request, String&& deviceIdentifierHashSalt)
+void RealtimeMediaSourceCenter::getDisplayMediaDevices(const MediaStreamRequest& request, Vector<DeviceInfo>& diaplayDeviceInfo, String& firstInvalidConstraint)
 {
-    struct DeviceInfo {
-        unsigned fitnessScore;
-        CaptureDevice device;
-    };
+    if (!request.videoConstraints.isValid)
+        return;
 
-    struct {
-        bool operator()(const DeviceInfo& a, const DeviceInfo& b)
-        {
-            return a.fitnessScore < b.fitnessScore;
-        }
-    } sortBasedOnFitnessScore;
+    String invalidConstraint;
+    for (auto& device : displayCaptureDeviceManager().captureDevices()) {
+        if (!device.enabled())
+            return;
 
-    Vector<DeviceInfo> audioDeviceInfo;
-    Vector<DeviceInfo> videoDeviceInfo;
+        auto sourceOrError = videoFactory().createVideoCaptureSource(device, { });
+        if (sourceOrError && sourceOrError.captureSource->supportsConstraints(request.videoConstraints, invalidConstraint))
+            diaplayDeviceInfo.append({sourceOrError.captureSource->fitnessScore(), device});
 
-    String firstInvalidConstraint;
-    for (auto& device : getMediaStreamDevices()) {
-        if (!device.enabled())
-            continue;
+        if (!invalidConstraint.isEmpty() && firstInvalidConstraint.isEmpty())
+            firstInvalidConstraint = invalidConstraint;
+    }
+}
 
-        String invalidConstraint;
-        CaptureSourceOrError sourceOrError;
-        switch (device.type()) {
-        case CaptureDevice::DeviceType::Camera: {
-            if (request.type != MediaStreamRequest::Type::UserMedia || !request.videoConstraints.isValid)
+void RealtimeMediaSourceCenter::getUserMediaDevices(const MediaStreamRequest& request, Vector<DeviceInfo>& audioDeviceInfo, Vector<DeviceInfo>& videoDeviceInfo, String& firstInvalidConstraint)
+{
+    String invalidConstraint;
+    if (request.audioConstraints.isValid) {
+        for (auto& device : audioCaptureDeviceManager().captureDevices()) {
+            if (!device.enabled())
                 continue;
 
-            auto sourceOrError = videoFactory().createVideoCaptureSource(device, { });
-            if (sourceOrError && sourceOrError.captureSource->supportsConstraints(request.videoConstraints, invalidConstraint))
-                videoDeviceInfo.append({sourceOrError.captureSource->fitnessScore(), device});
-            break;
+            auto sourceOrError = audioFactory().createAudioCaptureSource(device, { });
+            if (sourceOrError && sourceOrError.captureSource->supportsConstraints(request.audioConstraints, invalidConstraint))
+                audioDeviceInfo.append({sourceOrError.captureSource->fitnessScore(), device});
+
+            if (!invalidConstraint.isEmpty() && firstInvalidConstraint.isEmpty())
+                firstInvalidConstraint = invalidConstraint;
         }
-        case CaptureDevice::DeviceType::Microphone:
-            if (request.audioConstraints.isValid) {
-                auto sourceOrError = audioFactory().createAudioCaptureSource(device, { });
-                if (sourceOrError && sourceOrError.captureSource->supportsConstraints(request.audioConstraints, invalidConstraint))
-                    audioDeviceInfo.append({sourceOrError.captureSource->fitnessScore(), device});
-            }
-            break;
-        case CaptureDevice::DeviceType::Screen:
-        case CaptureDevice::DeviceType::Application:
-        case CaptureDevice::DeviceType::Window:
-        case CaptureDevice::DeviceType::Browser: {
-            if (request.type != MediaStreamRequest::Type::DisplayMedia)
-                continue;
-            ASSERT(request.audioConstraints.mandatoryConstraints.isEmpty());
-            ASSERT(request.videoConstraints.advancedConstraints.isEmpty());
-            if (!request.videoConstraints.isValid || !request.videoConstraints.advancedConstraints.isEmpty() || !request.videoConstraints.mandatoryConstraints.isEmpty())
+    }
+
+    if (request.videoConstraints.isValid) {
+        for (auto& device : videoCaptureDeviceManager().captureDevices()) {
+            if (!device.enabled())
                 continue;
 
             auto sourceOrError = videoFactory().createVideoCaptureSource(device, { });
             if (sourceOrError && sourceOrError.captureSource->supportsConstraints(request.videoConstraints, invalidConstraint))
                 videoDeviceInfo.append({sourceOrError.captureSource->fitnessScore(), device});
-            break;
+
+            if (!invalidConstraint.isEmpty() && firstInvalidConstraint.isEmpty())
+                firstInvalidConstraint = invalidConstraint;
         }
-        case CaptureDevice::DeviceType::Unknown:
-            ASSERT_NOT_REACHED();
-            break;
+    }
+}
+
+void RealtimeMediaSourceCenter::validateRequestConstraints(ValidConstraintsHandler&& validHandler, InvalidConstraintsHandler&& invalidHandler, const MediaStreamRequest& request, String&& deviceIdentifierHashSalt)
+{
+    struct {
+        bool operator()(const DeviceInfo& a, const DeviceInfo& b)
+        {
+            return a.fitnessScore < b.fitnessScore;
         }
+    } sortBasedOnFitnessScore;
 
-        if (!invalidConstraint.isEmpty() && firstInvalidConstraint.isEmpty())
-            firstInvalidConstraint = invalidConstraint;
-    }
+    Vector<DeviceInfo> audioDeviceInfo;
+    Vector<DeviceInfo> videoDeviceInfo;
+    String firstInvalidConstraint;
+
+    if (request.type == MediaStreamRequest::Type::DisplayMedia)
+        getDisplayMediaDevices(request, videoDeviceInfo, firstInvalidConstraint);
+    else
+        getUserMediaDevices(request, audioDeviceInfo, videoDeviceInfo, firstInvalidConstraint);
 
     if ((request.audioConstraints.isValid && audioDeviceInfo.isEmpty()) || (request.videoConstraints.isValid && videoDeviceInfo.isEmpty())) {
         invalidHandler(firstInvalidConstraint);
index d54ae8e..7627e98 100644 (file)
@@ -100,6 +100,15 @@ protected:
     CaptureDeviceManager* m_audioCaptureDeviceManager { nullptr };
     CaptureDeviceManager* m_videoCaptureDeviceManager { nullptr };
 
+private:
+    struct DeviceInfo {
+        unsigned fitnessScore;
+        CaptureDevice device;
+    };
+
+    void getDisplayMediaDevices(const MediaStreamRequest&, Vector<DeviceInfo>&, String&);
+    void getUserMediaDevices(const MediaStreamRequest&, Vector<DeviceInfo>& audioDevices, Vector<DeviceInfo>& videoDevices, String&);
+
     WTF::Function<void()> m_deviceChangedObserver;
 };