Commit e3d45995 authored by Francois Beaufort's avatar Francois Beaufort Committed by Commit Bot

[PTZ] Deny mandatory PTZ constraints in basic getUserMedia constraints

This PR makes sure required PTZ constraints in the basic constraint set
are denied (and throw a TypeError) and PTZ capability constraints
({ zoom: true } etc.) are ideal in the basic constraint set.
Therefore, a PTZ constraint in the basic set cannot cause getUserMedia()
to fail conditionally.

Spec:
https://github.com/w3c/mediacapture-image/pull/261
https://github.com/w3c/mediacapture-main/pull/707/

Bug: 934063
Change-Id: I7324ae32b064dbf3b89325166834e2694eca593b
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2411946
Commit-Queue: François Beaufort <beaufort.francois@gmail.com>
Reviewed-by: default avatarEero Häkkinen <eero.hakkinen@intel.com>
Reviewed-by: default avatarPhilip Jägenstedt <foolip@chromium.org>
Reviewed-by: default avatarGuido Urdaneta <guidou@chromium.org>
Reviewed-by: default avatarReilly Grant <reillyg@chromium.org>
Cr-Commit-Position: refs/heads/master@{#811242}
parent 666de7af
...@@ -457,19 +457,27 @@ class PTZDeviceState { ...@@ -457,19 +457,27 @@ class PTZDeviceState {
return pan_set_.IsEmpty() || tilt_set_.IsEmpty() || zoom_set_.IsEmpty(); return pan_set_.IsEmpty() || tilt_set_.IsEmpty() || zoom_set_.IsEmpty();
} }
double Fitness(const MediaTrackConstraintSetPlatform& basic_set) const { double Fitness(const MediaTrackConstraintSetPlatform& basic_set,
return NumericRangeFitness(basic_set.pan, pan_set_) + bool pan_tilt_zoom_supported) const {
double initial_fitness =
((basic_set.pan.IsPresent() || basic_set.tilt.IsPresent() ||
basic_set.zoom.IsPresent()) &&
!pan_tilt_zoom_supported)
? 1.0
: 0.0;
return initial_fitness + NumericRangeFitness(basic_set.pan, pan_set_) +
NumericRangeFitness(basic_set.tilt, tilt_set_) + NumericRangeFitness(basic_set.tilt, tilt_set_) +
NumericRangeFitness(basic_set.zoom, zoom_set_); NumericRangeFitness(basic_set.zoom, zoom_set_);
} }
const char* FailedConstraintName() const { const char* FailedConstraintName() const {
MediaTrackConstraintSetPlatform dummy; MediaTrackConstraintSetPlatform dummy;
if (!pan_set_.IsEmpty()) if (pan_set_.IsEmpty())
return dummy.pan.GetName(); return dummy.pan.GetName();
if (!tilt_set_.IsEmpty()) if (tilt_set_.IsEmpty())
return dummy.tilt.GetName(); return dummy.tilt.GetName();
if (!zoom_set_.IsEmpty()) if (zoom_set_.IsEmpty())
return dummy.zoom.GetName(); return dummy.zoom.GetName();
// No failed constraint. // No failed constraint.
...@@ -557,17 +565,17 @@ bool DeviceSatisfiesConstraintSet( ...@@ -557,17 +565,17 @@ bool DeviceSatisfiesConstraintSet(
return false; return false;
} }
if (constraint_set.pan.IsPresent() && !device.pan_tilt_zoom_supported) { if (constraint_set.pan.HasMandatory() && !device.pan_tilt_zoom_supported) {
UpdateFailedConstraintName(constraint_set.pan, failed_constraint_name); UpdateFailedConstraintName(constraint_set.pan, failed_constraint_name);
return false; return false;
} }
if (constraint_set.tilt.IsPresent() && !device.pan_tilt_zoom_supported) { if (constraint_set.tilt.HasMandatory() && !device.pan_tilt_zoom_supported) {
UpdateFailedConstraintName(constraint_set.tilt, failed_constraint_name); UpdateFailedConstraintName(constraint_set.tilt, failed_constraint_name);
return false; return false;
} }
if (constraint_set.zoom.IsPresent() && !device.pan_tilt_zoom_supported) { if (constraint_set.zoom.HasMandatory() && !device.pan_tilt_zoom_supported) {
UpdateFailedConstraintName(constraint_set.zoom, failed_constraint_name); UpdateFailedConstraintName(constraint_set.zoom, failed_constraint_name);
return false; return false;
} }
...@@ -614,7 +622,7 @@ double CandidateFitness(const DeviceInfo& device, ...@@ -614,7 +622,7 @@ double CandidateFitness(const DeviceInfo& device,
const MediaTrackConstraintSetPlatform& constraint_set, const MediaTrackConstraintSetPlatform& constraint_set,
VideoTrackAdapterSettings* track_settings) { VideoTrackAdapterSettings* track_settings) {
return DeviceFitness(device, constraint_set) + return DeviceFitness(device, constraint_set) +
ptz_state.Fitness(constraint_set) + ptz_state.Fitness(constraint_set, device.pan_tilt_zoom_supported) +
candidate_format.Fitness(constraint_set, track_settings) + candidate_format.Fitness(constraint_set, track_settings) +
OptionalBoolFitness(noise_reduction, OptionalBoolFitness(noise_reduction,
constraint_set.goog_noise_reduction); constraint_set.goog_noise_reduction);
......
...@@ -339,7 +339,21 @@ UserMediaRequest* UserMediaRequest::Create( ...@@ -339,7 +339,21 @@ UserMediaRequest* UserMediaRequest::Create(
if (error_state.HadException()) if (error_state.HadException())
return nullptr; return nullptr;
if (media_type == UserMediaRequest::MediaType::kDisplayMedia) { if (media_type == UserMediaRequest::MediaType::kUserMedia &&
!video.IsNull()) {
if (video.Basic().pan.HasMandatory()) {
error_state.ThrowTypeError("Mandatory pan constraint is not supported");
return nullptr;
}
if (video.Basic().tilt.HasMandatory()) {
error_state.ThrowTypeError("Mandatory tilt constraint is not supported");
return nullptr;
}
if (video.Basic().zoom.HasMandatory()) {
error_state.ThrowTypeError("Mandatory zoom constraint is not supported");
return nullptr;
}
} else if (media_type == UserMediaRequest::MediaType::kDisplayMedia) {
// https://w3c.github.io/mediacapture-screen-share/#mediadevices-additions // https://w3c.github.io/mediacapture-screen-share/#mediadevices-additions
// MediaDevices Additions // MediaDevices Additions
// The user agent MUST reject audio-only requests. // The user agent MUST reject audio-only requests.
......
<!doctype html>
<meta charset=utf-8>
<title>getUserMedia</title>
<script src="/resources/testharness.js"></script>
<script src="/resources/testharnessreport.js"></script>
<script>
"use strict";
[
{ video: { pan: { min: 1 } } },
{ video: { pan: { max: 1 } } },
{ video: { pan: { exact: 1 } } },
{ video: { tilt: { min: 1 } } },
{ video: { tilt: { max: 1 } } },
{ video: { tilt: { exact: 1 } } },
{ video: { zoom: { min: 1 } } },
{ video: { zoom: { max: 1 } } },
{ video: { zoom: { exact: 1 } } }
].forEach(constraints =>
promise_test(t => {
const promise = navigator.mediaDevices.getUserMedia(constraints);
return promise_rejects_js(t, TypeError, promise);
}, `getUserMedia(${JSON.stringify(constraints)}) must fail with TypeError`)
);
</script>
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment