Changeset 236465 in webkit
- Timestamp:
- Sep 25, 2018, 11:37:29 AM (8 years ago)
- Location:
- trunk
- Files:
-
- 9 edited
-
LayoutTests/ChangeLog (modified) (1 diff)
-
LayoutTests/http/tests/media/media-stream/get-display-media-prompt-expected.txt (modified) (1 diff)
-
LayoutTests/http/tests/media/media-stream/get-display-media-prompt.html (modified) (4 diffs)
-
Source/WebCore/ChangeLog (modified) (1 diff)
-
Source/WebCore/Modules/mediastream/MediaDevices.cpp (modified) (1 diff)
-
Source/WebCore/Modules/mediastream/UserMediaRequest.cpp (modified) (3 diffs)
-
Source/WebCore/Modules/mediastream/UserMediaRequest.h (modified) (1 diff)
-
Source/WebCore/platform/mediastream/RealtimeMediaSourceCenter.cpp (modified) (2 diffs)
-
Source/WebCore/platform/mediastream/RealtimeMediaSourceCenter.h (modified) (1 diff)
Legend:
- Unmodified
- Added
- Removed
-
trunk/LayoutTests/ChangeLog
r236461 r236465 1 2018-09-25 Eric Carlson <eric.carlson@apple.com> 2 3 [MediaStream] Update constraints supported by getDisplayMedia 4 https://bugs.webkit.org/show_bug.cgi?id=189930 5 6 Reviewed by Youenn Fablet. 7 8 * http/tests/media/media-stream/get-display-media-prompt-expected.txt: 9 * http/tests/media/media-stream/get-display-media-prompt.html: 10 1 11 2018-09-25 Ryan Haddad <ryanhaddad@apple.com> 2 12 -
trunk/LayoutTests/http/tests/media/media-stream/get-display-media-prompt-expected.txt
r226412 r236465 6 6 PASS numberOfTimesGetUserMediaPromptHasBeenCalled() is 0 7 7 8 ** Request an audio-only stream, the user should be prompted ** 9 PASS numberOfTimesGetUserMediaPromptHasBeenCalled() is 1 10 PASS stream.getAudioTracks().length is 1 11 PASS stream.getVideoTracks().length is 0 8 ** Request an audio-only stream, the user should not be prompted ** 9 PASS numberOfTimesGetUserMediaPromptHasBeenCalled() is 0 10 PASS stream is undefined. 11 PASS err instanceof Error is true 12 PASS err.name is "TypeError" 12 13 13 14 ** Request an video-only stream, the user should be prompted ** 15 PASS numberOfTimesGetUserMediaPromptHasBeenCalled() is 1 16 PASS stream.getAudioTracks().length is 0 17 PASS stream.getVideoTracks().length is 1 18 19 ** Request a stream with audio and video, the user should be prompted but no audio track should be created ** 14 20 PASS numberOfTimesGetUserMediaPromptHasBeenCalled() is 2 15 21 PASS stream.getAudioTracks().length is 0 16 22 PASS stream.getVideoTracks().length is 1 17 23 18 ** Request a stream with audio and video, the user should be prompted ** 24 ** Request a stream with 'max' constraints, the user should not be prompted ** 25 PASS numberOfTimesGetUserMediaPromptHasBeenCalled() is 2 26 PASS stream is undefined. 27 PASS err instanceof Error is true 28 PASS err.name is "TypeError" 29 30 ** Request a stream with 'min' constraints, the user should not be prompted ** 31 PASS numberOfTimesGetUserMediaPromptHasBeenCalled() is 2 32 PASS stream is undefined. 33 PASS err instanceof Error is true 34 PASS err.name is "TypeError" 35 36 ** Request a stream with 'advanced' constraints, the user should not be prompted ** 37 PASS numberOfTimesGetUserMediaPromptHasBeenCalled() is 2 38 PASS stream is undefined. 39 PASS err instanceof Error is true 40 PASS err.name is "TypeError" 41 42 ** Request a stream with valid constraints, the user should be prompted ** 19 43 PASS numberOfTimesGetUserMediaPromptHasBeenCalled() is 3 20 PASS stream.getAudioTracks().length is 144 PASS stream.getAudioTracks().length is 0 21 45 PASS stream.getVideoTracks().length is 1 22 46 23 ** Request a stream with invalid constraints, the user should not be prompted ** 24 PASS numberOfTimesGetUserMediaPromptHasBeenCalled() is 3 25 PASS stream is null 26 PASS err instanceof Error is true 27 PASS err.name is "InvalidAccessError" 47 ** Request a stream with an exact audio constraint, it should be ignored ** 48 PASS numberOfTimesGetUserMediaPromptHasBeenCalled() is 4 49 PASS stream.getAudioTracks().length is 0 50 PASS stream.getVideoTracks().length is 1 28 51 29 52 PASS successfullyParsed is true -
trunk/LayoutTests/http/tests/media/media-stream/get-display-media-prompt.html
r226412 r236465 19 19 20 20 async function promptForAudioOnly() { 21 debug("<br>** Request an audio-only stream, the user should be prompted **"); 22 stream = await navigator.mediaDevices.getDisplayMedia({ audio: true }); 23 shouldBe("numberOfTimesGetUserMediaPromptHasBeenCalled()", "1"); 24 shouldBe("stream.getAudioTracks().length", "1"); 25 shouldBe("stream.getVideoTracks().length", "0"); 21 debug("<br>** Request an audio-only stream, the user should not be prompted **"); 22 stream = await navigator.mediaDevices.getDisplayMedia({ audio: true }) 23 .catch((e) => { err = e; }); 24 shouldBe("numberOfTimesGetUserMediaPromptHasBeenCalled()", "0"); 25 shouldBeUndefined("stream"); 26 shouldBeTrue("err instanceof Error "); 27 shouldBeEqualToString("err.name", "TypeError"); 26 28 } 27 29 … … 29 31 debug("<br>** Request an video-only stream, the user should be prompted **"); 30 32 stream = await navigator.mediaDevices.getDisplayMedia({ video: true }); 31 shouldBe("numberOfTimesGetUserMediaPromptHasBeenCalled()", " 2");33 shouldBe("numberOfTimesGetUserMediaPromptHasBeenCalled()", "1"); 32 34 shouldBe("stream.getAudioTracks().length", "0"); 33 35 shouldBe("stream.getVideoTracks().length", "1"); … … 35 37 36 38 async function promptForAudioAndVideo() { 37 debug("<br>** Request a stream with audio and video, the user should be prompted **");39 debug("<br>** Request a stream with audio and video, the user should be prompted but no audio track should be created **"); 38 40 stream = await navigator.mediaDevices.getDisplayMedia({ video: true, audio: true }); 39 shouldBe("numberOfTimesGetUserMediaPromptHasBeenCalled()", " 3");40 shouldBe("stream.getAudioTracks().length", " 1");41 shouldBe("numberOfTimesGetUserMediaPromptHasBeenCalled()", "2"); 42 shouldBe("stream.getAudioTracks().length", "0"); 41 43 shouldBe("stream.getVideoTracks().length", "1"); 42 44 } 43 45 44 async function promptWithMediaTrackConstraints() { 45 debug("<br>** Request a stream with invalid constraints, the user should not be prompted **"); 46 async function promptWithExactVideoConstraints() { 47 debug("<br>** Request a stream with 'max' constraints, the user should not be prompted **"); 48 46 49 stream = null; 47 try { 48 stream = await navigator.mediaDevices.getDisplayMedia({ video: {width: {exact: 640}, height: {exact: 480}} }); 49 } catch (e) { 50 err = e; 51 } 50 stream = await navigator.mediaDevices.getDisplayMedia({ video: {width: {exact: 640}, height: {exact: 480}} }) 51 .catch((e) => { err = e; }); 52 53 shouldBe("numberOfTimesGetUserMediaPromptHasBeenCalled()", "2"); 54 shouldBeUndefined("stream"); 55 shouldBeTrue("err instanceof Error "); 56 shouldBeEqualToString("err.name", "TypeError"); 57 } 58 59 async function promptWithMinVideoConstraints() { 60 debug("<br>** Request a stream with 'min' constraints, the user should not be prompted **"); 61 62 stream = null; 63 stream = await navigator.mediaDevices.getDisplayMedia({ video: {width: {min: 640}, height: {min: 480}} }) 64 .catch((e) => { err = e; }); 65 shouldBe("numberOfTimesGetUserMediaPromptHasBeenCalled()", "2"); 66 shouldBeUndefined("stream"); 67 shouldBeTrue("err instanceof Error "); 68 shouldBeEqualToString("err.name", "TypeError"); 69 } 70 71 async function promptWithAdvancedVideoConstraints() { 72 debug("<br>** Request a stream with 'advanced' constraints, the user should not be prompted **"); 73 74 stream = null; 75 stream = await navigator.mediaDevices.getDisplayMedia({ video: { width: 640, height: 480, advanced: [ { width: 1920, height: 1280 } ] } }) 76 .catch((e) => { err = e; }); 77 shouldBe("numberOfTimesGetUserMediaPromptHasBeenCalled()", "2"); 78 shouldBeUndefined("stream"); 79 shouldBeTrue("err instanceof Error "); 80 shouldBeEqualToString("err.name", "TypeError"); 81 } 82 83 async function promptWithValidVideoConstraints() { 84 debug("<br>** Request a stream with valid constraints, the user should be prompted **"); 85 86 stream = null; 87 stream = await navigator.mediaDevices.getDisplayMedia({ video: {width: 640, height: 480} }) 88 .catch((e) => { err = e; }); 52 89 53 90 shouldBe("numberOfTimesGetUserMediaPromptHasBeenCalled()", "3"); 54 shouldBeNull("stream"); 55 shouldBeTrue("err instanceof Error "); 56 shouldBeEqualToString("err.name", "InvalidAccessError"); 91 shouldBe("stream.getAudioTracks().length", "0"); 92 shouldBe("stream.getVideoTracks().length", "1"); 57 93 } 58 94 95 async function promptWithInvalidAudioConstraint() { 96 debug("<br>** Request a stream with an exact audio constraint, it should be ignored **"); 97 98 stream = null; 99 stream = await navigator.mediaDevices.getDisplayMedia({ video: true, audio: { volume: { exact: 0.5 } } }); 100 shouldBe("numberOfTimesGetUserMediaPromptHasBeenCalled()", "4"); 101 shouldBe("stream.getAudioTracks().length", "0"); 102 shouldBe("stream.getVideoTracks().length", "1"); 103 } 104 59 105 (async function() { 60 106 description('Test basic getDisplayMedia prompting behavior'); … … 69 115 await promptForVideoOnly(); 70 116 await promptForAudioAndVideo(); 71 await promptWithMediaTrackConstraints(); 117 await promptWithExactVideoConstraints(); 118 await promptWithMinVideoConstraints(); 119 await promptWithAdvancedVideoConstraints(); 120 await promptWithValidVideoConstraints(); 121 await promptWithInvalidAudioConstraint(); 72 122 73 123 debug(""); -
trunk/Source/WebCore/ChangeLog
r236462 r236465 1 2018-09-25 Eric Carlson <eric.carlson@apple.com> 2 3 [MediaStream] Update constraints supported by getDisplayMedia 4 https://bugs.webkit.org/show_bug.cgi?id=189930 5 6 Reviewed by Youenn Fablet. 7 8 No new tests, updated http/tests/media/media-stream/get-display-media-prompt.html. 9 10 * Modules/mediastream/MediaDevices.cpp: 11 (WebCore::MediaDevices::getDisplayMedia const): Ignore audio constraints. 12 13 * Modules/mediastream/UserMediaRequest.cpp: 14 (WebCore::hasInvalidGetDisplayMediaConstraint): Check for invalid constraints. 15 (WebCore::UserMediaRequest::start): Check for invalid constraints. 16 (WebCore::UserMediaRequest::deny): Support new error. 17 * Modules/mediastream/UserMediaRequest.h: 18 19 * platform/mediastream/RealtimeMediaSourceCenter.cpp: 20 (WebCore::RealtimeMediaSourceCenter::validateRequestConstraints): 21 1 22 2018-09-25 Xabier Rodriguez Calvar <calvaris@igalia.com> 2 23 -
trunk/Source/WebCore/Modules/mediastream/MediaDevices.cpp
r235438 r236465 121 121 return Exception { InvalidStateError }; 122 122 123 auto request = UserMediaRequest::create(*document, { MediaStreamRequest::Type::DisplayMedia, createMediaConstraints(constraints.audio), createMediaConstraints(constraints.video) }, WTFMove(promise));123 auto request = UserMediaRequest::create(*document, { MediaStreamRequest::Type::DisplayMedia, { }, createMediaConstraints(constraints.video) }, WTFMove(promise)); 124 124 if (request) 125 125 request->start(); -
trunk/Source/WebCore/Modules/mediastream/UserMediaRequest.cpp
r236422 r236465 157 157 } 158 158 159 static bool hasInvalidGetDisplayMediaConstraint(const MediaConstraints& constraints) 160 { 161 // https://w3c.github.io/mediacapture-screen-share/#navigator-additions 162 // 1. Let constraints be the method's first argument. 163 // 2. For each member present in constraints whose value, value, is a dictionary, run the following steps: 164 // 1. If value contains a member named advanced, return a promise rejected with a newly created TypeError. 165 // 2. If value contains a member which in turn is a dictionary containing a member named either min or 166 // exact, return a promise rejected with a newly created TypeError. 167 if (!constraints.isValid) 168 return false; 169 170 if (!constraints.advancedConstraints.isEmpty()) 171 return true; 172 173 bool invalid = false; 174 constraints.mandatoryConstraints.filter([&invalid] (const MediaConstraint& constraint) mutable { 175 switch (constraint.constraintType()) { 176 case MediaConstraintType::Width: 177 case MediaConstraintType::Height: { 178 auto& intConstraint = downcast<IntConstraint>(constraint); 179 int value; 180 invalid = intConstraint.getExact(value) || intConstraint.getMin(value); 181 break; 182 } 183 184 case MediaConstraintType::AspectRatio: 185 case MediaConstraintType::FrameRate: { 186 auto& doubleConstraint = downcast<DoubleConstraint>(constraint); 187 double value; 188 invalid = doubleConstraint.getExact(value) || doubleConstraint.getMin(value); 189 break; 190 } 191 192 case MediaConstraintType::DisplaySurface: 193 case MediaConstraintType::LogicalSurface: { 194 auto& boolConstraint = downcast<BooleanConstraint>(constraint); 195 bool value; 196 invalid = boolConstraint.getExact(value); 197 break; 198 } 199 200 case MediaConstraintType::FacingMode: 201 case MediaConstraintType::DeviceId: 202 case MediaConstraintType::GroupId: { 203 auto& stringConstraint = downcast<StringConstraint>(constraint); 204 Vector<String> values; 205 invalid = stringConstraint.getExact(values); 206 break; 207 } 208 209 case MediaConstraintType::SampleRate: 210 case MediaConstraintType::SampleSize: 211 case MediaConstraintType::Volume: 212 case MediaConstraintType::EchoCancellation: 213 // Ignored. 214 break; 215 216 case MediaConstraintType::Unknown: 217 ASSERT_NOT_REACHED(); 218 break; 219 } 220 221 return invalid; 222 }); 223 224 return invalid; 225 } 226 159 227 void UserMediaRequest::start() 160 228 { … … 166 234 167 235 if (m_request.type == MediaStreamRequest::Type::DisplayMedia) { 168 // https://w3c.github.io/mediacapture-screen-share/#constraints 169 // 5.2 Constraining Display Surface Selection 170 // The getDisplayMedia function does not permit the use of constraints for selection of a source as described 171 // in the getUserMedia() algorithm. Prior to invoking the getUserMedia() algorithm, if either of the video 172 // and audio attributes are set to a MediaTrackConstraints value (as opposed to being absent or set to a 173 // Boolean value), reject the promise with a InvalidAccessError and abort. 174 if (m_request.videoConstraints.isValid && !(m_request.videoConstraints.mandatoryConstraints.isEmpty() && m_request.videoConstraints.advancedConstraints.isEmpty())) { 175 deny(MediaAccessDenialReason::InvalidAccess); 176 return; 177 } 178 179 if (m_request.audioConstraints.isValid && !(m_request.audioConstraints.mandatoryConstraints.isEmpty() && m_request.audioConstraints.advancedConstraints.isEmpty())) { 180 deny(MediaAccessDenialReason::InvalidAccess); 236 if (hasInvalidGetDisplayMediaConstraint(m_request.videoConstraints)) { 237 deny(MediaAccessDenialReason::IllegalConstraint); 181 238 return; 182 239 } … … 266 323 ExceptionCode code; 267 324 switch (reason) { 325 case MediaAccessDenialReason::IllegalConstraint: 326 RELEASE_LOG(MediaStream, "UserMediaRequest::deny - invalid constraints"); 327 code = TypeError; 328 break; 268 329 case MediaAccessDenialReason::NoConstraints: 269 330 RELEASE_LOG(MediaStream, "UserMediaRequest::deny - no constraints"); -
trunk/Source/WebCore/Modules/mediastream/UserMediaRequest.h
r233425 r236465 57 57 WEBCORE_EXPORT void allow(CaptureDevice&& audioDevice, CaptureDevice&& videoDevice, String&& deviceIdentifierHashSalt); 58 58 59 enum MediaAccessDenialReason { NoConstraints, UserMediaDisabled, NoCaptureDevices, InvalidConstraint, HardwareError, PermissionDenied, InvalidAccess, OtherFailure };59 enum MediaAccessDenialReason { NoConstraints, UserMediaDisabled, NoCaptureDevices, InvalidConstraint, HardwareError, PermissionDenied, InvalidAccess, IllegalConstraint, OtherFailure }; 60 60 WEBCORE_EXPORT void deny(MediaAccessDenialReason, const String& errorMessage = emptyString()); 61 61 -
trunk/Source/WebCore/platform/mediastream/RealtimeMediaSourceCenter.cpp
r235086 r236465 208 208 } 209 209 210 void RealtimeMediaSourceCenter::getDisplayMediaDevices(const MediaStreamRequest& request, Vector<DeviceInfo>& diaplayDeviceInfo, String& firstInvalidConstraint) 211 { 212 if (!request.videoConstraints.isValid) 213 return; 214 215 String invalidConstraint; 216 for (auto& device : displayCaptureDeviceManager().captureDevices()) { 217 if (!device.enabled()) 218 return; 219 220 auto sourceOrError = videoFactory().createVideoCaptureSource(device, { }); 221 if (sourceOrError && sourceOrError.captureSource->supportsConstraints(request.videoConstraints, invalidConstraint)) 222 diaplayDeviceInfo.append({sourceOrError.captureSource->fitnessScore(), device}); 223 224 if (!invalidConstraint.isEmpty() && firstInvalidConstraint.isEmpty()) 225 firstInvalidConstraint = invalidConstraint; 226 } 227 } 228 229 void RealtimeMediaSourceCenter::getUserMediaDevices(const MediaStreamRequest& request, Vector<DeviceInfo>& audioDeviceInfo, Vector<DeviceInfo>& videoDeviceInfo, String& firstInvalidConstraint) 230 { 231 String invalidConstraint; 232 if (request.audioConstraints.isValid) { 233 for (auto& device : audioCaptureDeviceManager().captureDevices()) { 234 if (!device.enabled()) 235 continue; 236 237 auto sourceOrError = audioFactory().createAudioCaptureSource(device, { }); 238 if (sourceOrError && sourceOrError.captureSource->supportsConstraints(request.audioConstraints, invalidConstraint)) 239 audioDeviceInfo.append({sourceOrError.captureSource->fitnessScore(), device}); 240 241 if (!invalidConstraint.isEmpty() && firstInvalidConstraint.isEmpty()) 242 firstInvalidConstraint = invalidConstraint; 243 } 244 } 245 246 if (request.videoConstraints.isValid) { 247 for (auto& device : videoCaptureDeviceManager().captureDevices()) { 248 if (!device.enabled()) 249 continue; 250 251 auto sourceOrError = videoFactory().createVideoCaptureSource(device, { }); 252 if (sourceOrError && sourceOrError.captureSource->supportsConstraints(request.videoConstraints, invalidConstraint)) 253 videoDeviceInfo.append({sourceOrError.captureSource->fitnessScore(), device}); 254 255 if (!invalidConstraint.isEmpty() && firstInvalidConstraint.isEmpty()) 256 firstInvalidConstraint = invalidConstraint; 257 } 258 } 259 } 260 210 261 void RealtimeMediaSourceCenter::validateRequestConstraints(ValidConstraintsHandler&& validHandler, InvalidConstraintsHandler&& invalidHandler, const MediaStreamRequest& request, String&& deviceIdentifierHashSalt) 211 262 { 212 struct DeviceInfo {213 unsigned fitnessScore;214 CaptureDevice device;215 };216 217 263 struct { 218 264 bool operator()(const DeviceInfo& a, const DeviceInfo& b) … … 224 270 Vector<DeviceInfo> audioDeviceInfo; 225 271 Vector<DeviceInfo> videoDeviceInfo; 226 227 272 String firstInvalidConstraint; 228 for (auto& device : getMediaStreamDevices()) { 229 if (!device.enabled()) 230 continue; 231 232 String invalidConstraint; 233 CaptureSourceOrError sourceOrError; 234 switch (device.type()) { 235 case CaptureDevice::DeviceType::Camera: { 236 if (request.type != MediaStreamRequest::Type::UserMedia || !request.videoConstraints.isValid) 237 continue; 238 239 auto sourceOrError = videoFactory().createVideoCaptureSource(device, { }); 240 if (sourceOrError && sourceOrError.captureSource->supportsConstraints(request.videoConstraints, invalidConstraint)) 241 videoDeviceInfo.append({sourceOrError.captureSource->fitnessScore(), device}); 242 break; 243 } 244 case CaptureDevice::DeviceType::Microphone: 245 if (request.audioConstraints.isValid) { 246 auto sourceOrError = audioFactory().createAudioCaptureSource(device, { }); 247 if (sourceOrError && sourceOrError.captureSource->supportsConstraints(request.audioConstraints, invalidConstraint)) 248 audioDeviceInfo.append({sourceOrError.captureSource->fitnessScore(), device}); 249 } 250 break; 251 case CaptureDevice::DeviceType::Screen: 252 case CaptureDevice::DeviceType::Application: 253 case CaptureDevice::DeviceType::Window: 254 case CaptureDevice::DeviceType::Browser: { 255 if (request.type != MediaStreamRequest::Type::DisplayMedia) 256 continue; 257 ASSERT(request.audioConstraints.mandatoryConstraints.isEmpty()); 258 ASSERT(request.videoConstraints.advancedConstraints.isEmpty()); 259 if (!request.videoConstraints.isValid || !request.videoConstraints.advancedConstraints.isEmpty() || !request.videoConstraints.mandatoryConstraints.isEmpty()) 260 continue; 261 262 auto sourceOrError = videoFactory().createVideoCaptureSource(device, { }); 263 if (sourceOrError && sourceOrError.captureSource->supportsConstraints(request.videoConstraints, invalidConstraint)) 264 videoDeviceInfo.append({sourceOrError.captureSource->fitnessScore(), device}); 265 break; 266 } 267 case CaptureDevice::DeviceType::Unknown: 268 ASSERT_NOT_REACHED(); 269 break; 270 } 271 272 if (!invalidConstraint.isEmpty() && firstInvalidConstraint.isEmpty()) 273 firstInvalidConstraint = invalidConstraint; 274 } 273 274 if (request.type == MediaStreamRequest::Type::DisplayMedia) 275 getDisplayMediaDevices(request, videoDeviceInfo, firstInvalidConstraint); 276 else 277 getUserMediaDevices(request, audioDeviceInfo, videoDeviceInfo, firstInvalidConstraint); 275 278 276 279 if ((request.audioConstraints.isValid && audioDeviceInfo.isEmpty()) || (request.videoConstraints.isValid && videoDeviceInfo.isEmpty())) { -
trunk/Source/WebCore/platform/mediastream/RealtimeMediaSourceCenter.h
r235086 r236465 101 101 CaptureDeviceManager* m_videoCaptureDeviceManager { nullptr }; 102 102 103 private: 104 struct DeviceInfo { 105 unsigned fitnessScore; 106 CaptureDevice device; 107 }; 108 109 void getDisplayMediaDevices(const MediaStreamRequest&, Vector<DeviceInfo>&, String&); 110 void getUserMediaDevices(const MediaStreamRequest&, Vector<DeviceInfo>& audioDevices, Vector<DeviceInfo>& videoDevices, String&); 111 103 112 WTF::Function<void()> m_deviceChangedObserver; 104 113 };
Note:
See TracChangeset
for help on using the changeset viewer.