Skip to content

Commit

Permalink
[PTZ] Support 'boolean or DoubleConstraint' in getUserMedia
Browse files Browse the repository at this point in the history
This CL adds 'boolean or DoubleConstraint' support for pan, tilt, and
zoom constraints in getUserMedia. Spec says that `pan: true` is just
syntactic sugar for `pan: {}` and `pan: false` the same as pan being
undefined/not provided.

Spec: w3c/mediacapture-image#225
Change-Id: I0f5788ff91bceda14bc9cdad0852e1195755a3f4
Bug: 934063
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2210237
Reviewed-by: Guido Urdaneta <[email protected]>
Reviewed-by: Kentaro Hara <[email protected]>
Commit-Queue: François Beaufort <[email protected]>
Cr-Commit-Position: refs/heads/master@{#773060}
  • Loading branch information
beaufortfrancois authored and Commit Bot committed May 29, 2020
1 parent 9270409 commit 62ee933
Show file tree
Hide file tree
Showing 9 changed files with 183 additions and 79 deletions.
101 changes: 91 additions & 10 deletions chrome/browser/media/webrtc/webrtc_pan_tilt_zoom_browsertest.cc
Original file line number Diff line number Diff line change
Expand Up @@ -70,34 +70,115 @@ INSTANTIATE_TEST_SUITE_P(
RequestPanTiltZoomPermission,
WebRtcPanTiltZoomBrowserTest,
testing::Values(
// no pan, tilt, zoom in audio and video constraints
TestConfig{"{ video: true }", "prompt", "granted", "prompt"},
TestConfig{"{ audio: true }", "granted", "prompt", "prompt"},
TestConfig{"{ audio: true, video: true }", "granted", "granted",
"prompt"},
TestConfig{"{ video: { pan : {} } }", "prompt", "granted", "prompt"},
TestConfig{"{ video: { tilt : {} } }", "prompt", "granted", "prompt"},
TestConfig{"{ video: { zoom : {} } }", "prompt", "granted", "prompt"},
TestConfig{"{ video: { advanced: [{ pan : {} }] } }", "prompt",
"granted", "prompt"},
TestConfig{"{ video: { advanced: [{ tilt : {} }] } }", "prompt",
"granted", "prompt"},
TestConfig{"{ video: { advanced: [{ zoom : {} }] } }", "prompt",
"granted", "prompt"},
// pan, tilt, zoom in audio constraints
TestConfig{"{ audio: { pan : false } }", "granted", "prompt", "prompt"},
TestConfig{"{ audio: { tilt : false } }", "granted", "prompt",
"prompt"},
TestConfig{"{ audio: { zoom : false } }", "granted", "prompt",
"prompt"},
TestConfig{"{ audio: { pan : {} } }", "granted", "prompt", "prompt"},
TestConfig{"{ audio: { tilt : {} } }", "granted", "prompt", "prompt"},
TestConfig{"{ audio: { zoom : {} } }", "granted", "prompt", "prompt"},
TestConfig{"{ audio: { pan : 1 } }", "granted", "prompt", "prompt"},
TestConfig{"{ audio: { tilt : 1 } }", "granted", "prompt", "prompt"},
TestConfig{"{ audio: { zoom : 1 } }", "granted", "prompt", "prompt"},
TestConfig{"{ audio: { pan : true } }", "granted", "prompt", "prompt"},
TestConfig{"{ audio: { tilt : true } }", "granted", "prompt", "prompt"},
TestConfig{"{ audio: { zoom : true } }", "granted", "prompt", "prompt"},
// pan, tilt, zoom in basic video constraints if no audio
TestConfig{"{ video: { pan : false } }", "prompt", "granted", "prompt"},
TestConfig{"{ video: { tilt : false } }", "prompt", "granted",
"prompt"},
TestConfig{"{ video: { zoom : false } }", "prompt", "granted",
"prompt"},
TestConfig{"{ video: { pan : {} } }", "prompt", "granted", "granted"},
TestConfig{"{ video: { tilt : {} } }", "prompt", "granted", "granted"},
TestConfig{"{ video: { zoom : {} } }", "prompt", "granted", "granted"},
TestConfig{"{ video: { pan : 1 } }", "prompt", "granted", "granted"},
TestConfig{"{ video: { tilt : 1 } }", "prompt", "granted", "granted"},
TestConfig{"{ video: { zoom : 1 } }", "prompt", "granted", "granted"},
TestConfig{"{ video: { pan : true } }", "prompt", "granted", "granted"},
TestConfig{"{ video: { tilt : true } }", "prompt", "granted",
"granted"},
TestConfig{"{ video: { zoom : true } }", "prompt", "granted",
"granted"},
// pan, tilt, zoom in advanced video constraints if no audio
TestConfig{"{ video: { advanced: [{ pan : false }] } }", "prompt",
"granted", "prompt"},
TestConfig{"{ video: { advanced: [{ tilt : false }] } }", "prompt",
"granted", "prompt"},
TestConfig{"{ video: { advanced: [{ zoom : false }] } }", "prompt",
"granted", "prompt"},
TestConfig{"{ video: { advanced: [{ pan : {} }] } }", "prompt",
"granted", "granted"},
TestConfig{"{ video: { advanced: [{ tilt : {} }] } }", "prompt",
"granted", "granted"},
TestConfig{"{ video: { advanced: [{ zoom : {} }] } }", "prompt",
"granted", "granted"},
TestConfig{"{ video: { advanced: [{ pan : 1 }] } }", "prompt",
"granted", "granted"},
TestConfig{"{ video: { advanced: [{ tilt : 1 }] } }", "prompt",
"granted", "granted"},
TestConfig{"{ video: { advanced: [{ zoom : 1 }] } }", "prompt",
"granted", "granted"},
TestConfig{"{ video: { advanced: [{ pan : true }] } }", "prompt",
"granted", "granted"},
TestConfig{"{ video: { advanced: [{ tilt : true }] } }", "prompt",
"granted", "granted"},
TestConfig{"{ video: { advanced: [{ zoom : true }] } }", "prompt",
"granted", "granted"},
// pan, tilt, zoom in basic video constraints if audio
TestConfig{"{ audio: true, video: { pan : false } }", "granted",
"granted", "prompt"},
TestConfig{"{ audio: true, video: { tilt : false } }", "granted",
"granted", "prompt"},
TestConfig{"{ audio: true, video: { zoom : false } }", "granted",
"granted", "prompt"},
TestConfig{"{ audio: true, video: { pan : {} } }", "granted", "granted",
"granted"},
TestConfig{"{ audio: true, video: { tilt : {} } }", "granted",
"granted", "granted"},
TestConfig{"{ audio: true, video: { zoom : {} } }", "granted",
"granted", "granted"},
TestConfig{"{ audio: true, video: { pan : 1 } }", "granted", "granted",
"granted"},
TestConfig{"{ audio: true, video: { tilt : 1 } }", "granted", "granted",
"granted"},
TestConfig{"{ audio: true, video: { zoom : 1 } }", "granted", "granted",
"granted"}));
"granted"},
TestConfig{"{ audio: true, video: { pan : true } }", "granted",
"granted", "granted"},
TestConfig{"{ audio: true, video: { tilt : true } }", "granted",
"granted", "granted"},
TestConfig{"{ audio: true, video: { zoom : true } }", "granted",
"granted", "granted"},
// pan, tilt, zoom in advanced video constraints if audio
TestConfig{"{ audio: true, video: { advanced: [{ pan : false }] } }",
"granted", "granted", "prompt"},
TestConfig{"{ audio: true, video: { advanced: [{ tilt : false }] } }",
"granted", "granted", "prompt"},
TestConfig{"{ audio: true, video: { advanced: [{ zoom : false }] } }",
"granted", "granted", "prompt"},
TestConfig{"{ audio: true, video: { advanced: [{ pan : {} }] } }",
"granted", "granted", "granted"},
TestConfig{"{ audio: true, video: { advanced: [{ tilt : {} }] } }",
"granted", "granted", "granted"},
TestConfig{"{ audio: true, video: { advanced: [{ zoom : {} }] } }",
"granted", "granted", "granted"},
TestConfig{"{ audio: true, video: { advanced: [{ pan : 1 }] } }",
"granted", "granted", "granted"},
TestConfig{"{ audio: true, video: { advanced: [{ tilt : 1 }] } }",
"granted", "granted", "granted"},
TestConfig{"{ audio: true, video: { advanced: [{ zoom : 1 }] } }",
"granted", "granted", "granted"},
TestConfig{"{ audio: true, video: { advanced: [{ pan : true }] } }",
"granted", "granted", "granted"},
TestConfig{"{ audio: true, video: { advanced: [{ tilt : true }] } }",
"granted", "granted", "granted"},
TestConfig{"{ audio: true, video: { advanced: [{ zoom : true }] } }",
"granted", "granted", "granted"}));
2 changes: 2 additions & 0 deletions third_party/blink/renderer/bindings/modules/v8/generated.gni
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,8 @@ bindings_modules_generated_union_type_files = [
"$bindings_modules_v8_output_dir/audio_context_latency_category_or_double.h",
"$bindings_modules_v8_output_dir/boolean_or_constrain_boolean_parameters.cc",
"$bindings_modules_v8_output_dir/boolean_or_constrain_boolean_parameters.h",
"$bindings_modules_v8_output_dir/boolean_or_double_or_constrain_double_range.cc",
"$bindings_modules_v8_output_dir/boolean_or_double_or_constrain_double_range.h",
"$bindings_modules_v8_output_dir/boolean_or_media_track_constraints.cc",
"$bindings_modules_v8_output_dir/boolean_or_media_track_constraints.h",
"$bindings_modules_v8_output_dir/canvas_image_source.cc",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -497,6 +497,7 @@ MediaConstraints Create(ExecutionContext* context,
void CopyLongConstraint(const LongOrConstrainLongRange& blink_union_form,
NakedValueDisposition naked_treatment,
LongConstraint& web_form) {
web_form.SetIsPresent(true);
if (blink_union_form.IsLong()) {
switch (naked_treatment) {
case NakedValueDisposition::kTreatAsIdeal:
Expand Down Expand Up @@ -526,6 +527,7 @@ void CopyLongConstraint(const LongOrConstrainLongRange& blink_union_form,
void CopyDoubleConstraint(const DoubleOrConstrainDoubleRange& blink_union_form,
NakedValueDisposition naked_treatment,
DoubleConstraint& web_form) {
web_form.SetIsPresent(true);
if (blink_union_form.IsDouble()) {
switch (naked_treatment) {
case NakedValueDisposition::kTreatAsIdeal:
Expand All @@ -552,11 +554,31 @@ void CopyDoubleConstraint(const DoubleOrConstrainDoubleRange& blink_union_form,
}
}

void CopyBooleanOrDoubleConstraint(
const BooleanOrDoubleOrConstrainDoubleRange& blink_union_form,
NakedValueDisposition naked_treatment,
DoubleConstraint& web_form) {
if (blink_union_form.IsBoolean()) {
web_form.SetIsPresent(blink_union_form.GetAsBoolean());
return;
}
DoubleOrConstrainDoubleRange double_constraint;
if (blink_union_form.IsDouble()) {
double_constraint.SetDouble(blink_union_form.GetAsDouble());
} else {
DCHECK(blink_union_form.IsConstrainDoubleRange());
double_constraint.SetConstrainDoubleRange(
blink_union_form.GetAsConstrainDoubleRange());
}
CopyDoubleConstraint(double_constraint, naked_treatment, web_form);
}

void CopyStringConstraint(
const StringOrStringSequenceOrConstrainDOMStringParameters&
blink_union_form,
NakedValueDisposition naked_treatment,
StringConstraint& web_form) {
web_form.SetIsPresent(true);
if (blink_union_form.IsString()) {
switch (naked_treatment) {
case NakedValueDisposition::kTreatAsIdeal:
Expand Down Expand Up @@ -601,6 +623,7 @@ void CopyBooleanConstraint(
const BooleanOrConstrainBooleanParameters& blink_union_form,
NakedValueDisposition naked_treatment,
BooleanConstraint& web_form) {
web_form.SetIsPresent(true);
if (blink_union_form.IsBoolean()) {
switch (naked_treatment) {
case NakedValueDisposition::kTreatAsIdeal:
Expand Down Expand Up @@ -689,16 +712,16 @@ void CopyConstraintSet(const MediaTrackConstraintSet* constraints_in,
constraint_buffer.video_kind);
}
if (constraints_in->hasPan()) {
CopyDoubleConstraint(constraints_in->pan(), naked_treatment,
constraint_buffer.pan);
CopyBooleanOrDoubleConstraint(constraints_in->pan(), naked_treatment,
constraint_buffer.pan);
}
if (constraints_in->hasTilt()) {
CopyDoubleConstraint(constraints_in->tilt(), naked_treatment,
constraint_buffer.tilt);
CopyBooleanOrDoubleConstraint(constraints_in->tilt(), naked_treatment,
constraint_buffer.tilt);
}
if (constraints_in->hasZoom()) {
CopyDoubleConstraint(constraints_in->zoom(), naked_treatment,
constraint_buffer.zoom);
CopyBooleanOrDoubleConstraint(constraints_in->zoom(), naked_treatment,
constraint_buffer.zoom);
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -116,6 +116,32 @@ TEST(MediaTrackConstraintsTest, ConstraintsToString) {

MediaConstraints null_constraints;
EXPECT_EQ("", null_constraints.ToString().Utf8());

MediaConstraints pan_constraints;
MediaTrackConstraintSetPlatform pan_basic;
Vector<MediaTrackConstraintSetPlatform> pan_advanced(static_cast<size_t>(1));
pan_basic.pan.SetIsPresent(false);
pan_advanced[0].pan.SetIsPresent(true);
pan_constraints.Initialize(pan_basic, pan_advanced);
EXPECT_EQ("{advanced: [{pan: {}}]}", pan_constraints.ToString().Utf8());

MediaConstraints tilt_constraints;
MediaTrackConstraintSetPlatform tilt_basic;
Vector<MediaTrackConstraintSetPlatform> tilt_advanced(static_cast<size_t>(1));
tilt_basic.tilt.SetIsPresent(false);
tilt_advanced[0].tilt.SetIsPresent(true);
tilt_constraints.Initialize(tilt_basic, tilt_advanced);
EXPECT_EQ("{advanced: [{tilt: {}}]}", tilt_constraints.ToString().Utf8());

MediaConstraints zoom_constraints;
MediaTrackConstraintSetPlatform zoom_basic;
Vector<MediaTrackConstraintSetPlatform> zoom_advanced(static_cast<size_t>(1));
zoom_basic.zoom.SetIsPresent(false);
zoom_advanced[0].zoom.SetIsPresent(true);
zoom_constraints.Initialize(zoom_basic, zoom_advanced);
EXPECT_EQ("{advanced: [{zoom: {}}]}", zoom_constraints.ToString().Utf8());

// TODO(crbug.com/1086338): Test other constraints with IsPresent.
}

TEST(MediaTrackConstraintsTest, ConvertWebConstraintsBasic) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -48,9 +48,9 @@ dictionary MediaTrackConstraintSet {
ConstrainDouble saturation;
ConstrainDouble sharpness;
ConstrainDouble focusDistance;
[RuntimeEnabled=MediaCapturePanTilt] ConstrainDouble pan;
[RuntimeEnabled=MediaCapturePanTilt] ConstrainDouble tilt;
ConstrainDouble zoom;
[RuntimeEnabled=MediaCapturePanTilt] (boolean or ConstrainDouble) pan;
[RuntimeEnabled=MediaCapturePanTilt] (boolean or ConstrainDouble) tilt;
(boolean or ConstrainDouble) zoom;
ConstrainBoolean torch;
// The "mandatory" and "_optional" members are retained for conformance
// with https://www.w3.org/TR/2013/WD-mediacapture-streams-20130903/
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1460,81 +1460,48 @@ TEST_F(UserMediaClientTest, PanConstraintRequestPanTiltZoomPermission) {
EXPECT_FALSE(UserMediaProcessor::IsPanTiltZoomPermissionRequested(
CreateDefaultConstraints()));

blink::MockConstraintFactory exact_basic_factory;
exact_basic_factory.basic().pan.SetExact(1);
blink::MockConstraintFactory basic_factory;
basic_factory.basic().pan.SetIsPresent(true);
EXPECT_TRUE(UserMediaProcessor::IsPanTiltZoomPermissionRequested(
exact_basic_factory.CreateMediaConstraints()));
basic_factory.CreateMediaConstraints()));

blink::MockConstraintFactory ideal_basic_factory;
ideal_basic_factory.basic().pan.SetIdeal(1);
blink::MockConstraintFactory advanced_factory;
auto& exact_advanced = advanced_factory.AddAdvanced();
exact_advanced.pan.SetIsPresent(true);
EXPECT_TRUE(UserMediaProcessor::IsPanTiltZoomPermissionRequested(
ideal_basic_factory.CreateMediaConstraints()));

blink::MockConstraintFactory exact_advanced_factory;
auto& exact_advanced = exact_advanced_factory.AddAdvanced();
exact_advanced.pan.SetExact(1);
EXPECT_TRUE(UserMediaProcessor::IsPanTiltZoomPermissionRequested(
exact_advanced_factory.CreateMediaConstraints()));

blink::MockConstraintFactory ideal_advanced_factory;
auto& ideal_advanced = ideal_advanced_factory.AddAdvanced();
ideal_advanced.pan.SetIdeal(1);
EXPECT_TRUE(UserMediaProcessor::IsPanTiltZoomPermissionRequested(
ideal_advanced_factory.CreateMediaConstraints()));
advanced_factory.CreateMediaConstraints()));
}

TEST_F(UserMediaClientTest, TiltConstraintRequestPanTiltZoomPermission) {
EXPECT_FALSE(UserMediaProcessor::IsPanTiltZoomPermissionRequested(
CreateDefaultConstraints()));

blink::MockConstraintFactory exact_basic_factory;
exact_basic_factory.basic().tilt.SetExact(1);
EXPECT_TRUE(UserMediaProcessor::IsPanTiltZoomPermissionRequested(
exact_basic_factory.CreateMediaConstraints()));

blink::MockConstraintFactory ideal_basic_factory;
ideal_basic_factory.basic().tilt.SetIdeal(1);
blink::MockConstraintFactory basic_factory;
basic_factory.basic().tilt.SetIsPresent(true);
EXPECT_TRUE(UserMediaProcessor::IsPanTiltZoomPermissionRequested(
ideal_basic_factory.CreateMediaConstraints()));
basic_factory.CreateMediaConstraints()));

blink::MockConstraintFactory exact_advanced_factory;
auto& exact_advanced = exact_advanced_factory.AddAdvanced();
exact_advanced.tilt.SetExact(1);
blink::MockConstraintFactory advanced_factory;
auto& exact_advanced = advanced_factory.AddAdvanced();
exact_advanced.tilt.SetIsPresent(true);
EXPECT_TRUE(UserMediaProcessor::IsPanTiltZoomPermissionRequested(
exact_advanced_factory.CreateMediaConstraints()));

blink::MockConstraintFactory ideal_advanced_factory;
auto& ideal_advanced = ideal_advanced_factory.AddAdvanced();
ideal_advanced.tilt.SetIdeal(1);
EXPECT_TRUE(UserMediaProcessor::IsPanTiltZoomPermissionRequested(
ideal_advanced_factory.CreateMediaConstraints()));
advanced_factory.CreateMediaConstraints()));
}

TEST_F(UserMediaClientTest, ZoomConstraintRequestPanTiltZoomPermission) {
EXPECT_FALSE(UserMediaProcessor::IsPanTiltZoomPermissionRequested(
CreateDefaultConstraints()));

blink::MockConstraintFactory exact_basic_factory;
exact_basic_factory.basic().zoom.SetExact(1);
EXPECT_TRUE(UserMediaProcessor::IsPanTiltZoomPermissionRequested(
exact_basic_factory.CreateMediaConstraints()));

blink::MockConstraintFactory ideal_basic_factory;
ideal_basic_factory.basic().zoom.SetIdeal(1);
EXPECT_TRUE(UserMediaProcessor::IsPanTiltZoomPermissionRequested(
ideal_basic_factory.CreateMediaConstraints()));

blink::MockConstraintFactory exact_advanced_factory;
auto& exact_advanced = exact_advanced_factory.AddAdvanced();
exact_advanced.zoom.SetExact(1);
blink::MockConstraintFactory basic_factory;
basic_factory.basic().zoom.SetIsPresent(true);
EXPECT_TRUE(UserMediaProcessor::IsPanTiltZoomPermissionRequested(
exact_advanced_factory.CreateMediaConstraints()));
basic_factory.CreateMediaConstraints()));

blink::MockConstraintFactory ideal_advanced_factory;
auto& ideal_advanced = ideal_advanced_factory.AddAdvanced();
ideal_advanced.zoom.SetIdeal(1);
blink::MockConstraintFactory advanced_factory;
auto& exact_advanced = advanced_factory.AddAdvanced();
exact_advanced.zoom.SetIsPresent(true);
EXPECT_TRUE(UserMediaProcessor::IsPanTiltZoomPermissionRequested(
ideal_advanced_factory.CreateMediaConstraints()));
advanced_factory.CreateMediaConstraints()));
}

} // namespace blink
Original file line number Diff line number Diff line change
Expand Up @@ -812,15 +812,15 @@ bool UserMediaProcessor::IsPanTiltZoomPermissionRequested(
if (!RuntimeEnabledFeatures::MediaCapturePanTiltEnabled())
return false;

if (!constraints.Basic().pan.IsEmpty() ||
!constraints.Basic().tilt.IsEmpty() ||
!constraints.Basic().zoom.IsEmpty()) {
if (constraints.Basic().pan.IsPresent() ||
constraints.Basic().tilt.IsPresent() ||
constraints.Basic().zoom.IsPresent()) {
return true;
}

for (const auto& advanced_set : constraints.Advanced()) {
if (!advanced_set.pan.IsEmpty() || !advanced_set.tilt.IsEmpty() ||
!advanced_set.zoom.IsEmpty()) {
if (advanced_set.pan.IsPresent() || advanced_set.tilt.IsPresent() ||
advanced_set.zoom.IsPresent()) {
return true;
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -498,7 +498,7 @@ String MediaTrackConstraintSetPlatform::ToString() const {
StringBuilder builder;
bool first = true;
for (auto* const constraint : AllConstraints()) {
if (!constraint->IsEmpty()) {
if (constraint->IsPresent()) {
if (!first)
builder.Append(", ");
builder.Append(constraint->GetName());
Expand Down
Loading

0 comments on commit 62ee933

Please sign in to comment.