| Index: third_party/WebKit/Source/modules/mediastream/UserMediaRequest.cpp
 | 
| diff --git a/third_party/WebKit/Source/modules/mediastream/UserMediaRequest.cpp b/third_party/WebKit/Source/modules/mediastream/UserMediaRequest.cpp
 | 
| index 51287a578a7adcdecce96b681a2ef061238f3f00..503dd846091b7bf4dca198fdc0670d4eb747c22f 100644
 | 
| --- a/third_party/WebKit/Source/modules/mediastream/UserMediaRequest.cpp
 | 
| +++ b/third_party/WebKit/Source/modules/mediastream/UserMediaRequest.cpp
 | 
| @@ -31,6 +31,8 @@
 | 
|  
 | 
|  #include "modules/mediastream/UserMediaRequest.h"
 | 
|  
 | 
| +#include <type_traits>
 | 
| +
 | 
|  #include "bindings/core/v8/Dictionary.h"
 | 
|  #include "bindings/core/v8/ExceptionMessages.h"
 | 
|  #include "bindings/core/v8/ExceptionState.h"
 | 
| @@ -49,10 +51,259 @@
 | 
|  
 | 
|  namespace blink {
 | 
|  
 | 
| -static WebMediaConstraints ParseOptions(
 | 
| -    ExecutionContext* context,
 | 
| -    const BooleanOrMediaTrackConstraints& options,
 | 
| -    MediaErrorState& error_state) {
 | 
| +namespace {
 | 
| +
 | 
| +template <typename NumericConstraint>
 | 
| +bool SetUsesNumericConstraint(
 | 
| +    const WebMediaTrackConstraintSet& set,
 | 
| +    NumericConstraint WebMediaTrackConstraintSet::*field) {
 | 
| +  return (set.*field).HasExact() || (set.*field).HasIdeal() ||
 | 
| +         (set.*field).HasMin() || (set.*field).HasMax();
 | 
| +}
 | 
| +
 | 
| +template <typename DiscreteConstraint>
 | 
| +bool SetUsesDiscreteConstraint(
 | 
| +    const WebMediaTrackConstraintSet& set,
 | 
| +    DiscreteConstraint WebMediaTrackConstraintSet::*field) {
 | 
| +  return (set.*field).HasExact() || (set.*field).HasIdeal();
 | 
| +}
 | 
| +
 | 
| +template <typename NumericConstraint>
 | 
| +bool RequestUsesNumericConstraint(
 | 
| +    const WebMediaConstraints& constraints,
 | 
| +    NumericConstraint WebMediaTrackConstraintSet::*field) {
 | 
| +  if (SetUsesNumericConstraint(constraints.Basic(), field))
 | 
| +    return true;
 | 
| +  for (const auto& advanced_set : constraints.Advanced()) {
 | 
| +    if (SetUsesNumericConstraint(advanced_set, field))
 | 
| +      return true;
 | 
| +  }
 | 
| +  return false;
 | 
| +}
 | 
| +
 | 
| +template <typename DiscreteConstraint>
 | 
| +bool RequestUsesDiscreteConstraint(
 | 
| +    const WebMediaConstraints& constraints,
 | 
| +    DiscreteConstraint WebMediaTrackConstraintSet::*field) {
 | 
| +  static_assert(
 | 
| +      std::is_same<decltype(field),
 | 
| +                   StringConstraint WebMediaTrackConstraintSet::*>::value ||
 | 
| +          std::is_same<decltype(field),
 | 
| +                       BooleanConstraint WebMediaTrackConstraintSet::*>::value,
 | 
| +      "Must use StringConstraint or BooleanConstraint");
 | 
| +  if (SetUsesDiscreteConstraint(constraints.Basic(), field))
 | 
| +    return true;
 | 
| +  for (const auto& advanced_set : constraints.Advanced()) {
 | 
| +    if (SetUsesDiscreteConstraint(advanced_set, field))
 | 
| +      return true;
 | 
| +  }
 | 
| +  return false;
 | 
| +}
 | 
| +
 | 
| +class FeatureCounter {
 | 
| +  WTF_MAKE_NONCOPYABLE(FeatureCounter);
 | 
| +
 | 
| + public:
 | 
| +  FeatureCounter(ExecutionContext* context)
 | 
| +      : context_(context), is_unconstrained_(true) {}
 | 
| +  void Count(UseCounter::Feature feature) {
 | 
| +    UseCounter::Count(context_, feature);
 | 
| +    is_unconstrained_ = false;
 | 
| +  }
 | 
| +  bool IsUnconstrained() { return is_unconstrained_; }
 | 
| +
 | 
| + private:
 | 
| +  Persistent<ExecutionContext> context_;
 | 
| +  bool is_unconstrained_;
 | 
| +};
 | 
| +
 | 
| +void CountAudioConstraintUses(ExecutionContext* context,
 | 
| +                              const WebMediaConstraints& constraints) {
 | 
| +  FeatureCounter counter(context);
 | 
| +  if (RequestUsesNumericConstraint(constraints,
 | 
| +                                   &WebMediaTrackConstraintSet::sample_rate)) {
 | 
| +    counter.Count(UseCounter::kMediaStreamConstraintsSampleRate);
 | 
| +  }
 | 
| +  if (RequestUsesNumericConstraint(constraints,
 | 
| +                                   &WebMediaTrackConstraintSet::sample_size)) {
 | 
| +    counter.Count(UseCounter::kMediaStreamConstraintsSampleSize);
 | 
| +  }
 | 
| +  if (RequestUsesDiscreteConstraint(
 | 
| +          constraints, &WebMediaTrackConstraintSet::echo_cancellation)) {
 | 
| +    counter.Count(UseCounter::kMediaStreamConstraintsEchoCancellation);
 | 
| +  }
 | 
| +  if (RequestUsesNumericConstraint(constraints,
 | 
| +                                   &WebMediaTrackConstraintSet::latency)) {
 | 
| +    counter.Count(UseCounter::kMediaStreamConstraintsLatency);
 | 
| +  }
 | 
| +  if (RequestUsesNumericConstraint(
 | 
| +          constraints, &WebMediaTrackConstraintSet::channel_count)) {
 | 
| +    counter.Count(UseCounter::kMediaStreamConstraintsChannelCount);
 | 
| +  }
 | 
| +  if (RequestUsesDiscreteConstraint(constraints,
 | 
| +                                    &WebMediaTrackConstraintSet::device_id)) {
 | 
| +    counter.Count(UseCounter::kMediaStreamConstraintsDeviceIdAudio);
 | 
| +  }
 | 
| +  if (RequestUsesDiscreteConstraint(
 | 
| +          constraints, &WebMediaTrackConstraintSet::disable_local_echo)) {
 | 
| +    counter.Count(UseCounter::kMediaStreamConstraintsDisableLocalEcho);
 | 
| +  }
 | 
| +  if (RequestUsesDiscreteConstraint(constraints,
 | 
| +                                    &WebMediaTrackConstraintSet::group_id)) {
 | 
| +    counter.Count(UseCounter::kMediaStreamConstraintsGroupIdAudio);
 | 
| +  }
 | 
| +  if (RequestUsesDiscreteConstraint(
 | 
| +          constraints, &WebMediaTrackConstraintSet::media_stream_source)) {
 | 
| +    counter.Count(UseCounter::kMediaStreamConstraintsMediaStreamSourceAudio);
 | 
| +  }
 | 
| +  if (RequestUsesDiscreteConstraint(
 | 
| +          constraints,
 | 
| +          &WebMediaTrackConstraintSet::render_to_associated_sink)) {
 | 
| +    counter.Count(UseCounter::kMediaStreamConstraintsRenderToAssociatedSink);
 | 
| +  }
 | 
| +  if (RequestUsesDiscreteConstraint(
 | 
| +          constraints, &WebMediaTrackConstraintSet::hotword_enabled)) {
 | 
| +    counter.Count(UseCounter::kMediaStreamConstraintsHotwordEnabled);
 | 
| +  }
 | 
| +  if (RequestUsesDiscreteConstraint(
 | 
| +          constraints, &WebMediaTrackConstraintSet::goog_echo_cancellation)) {
 | 
| +    counter.Count(UseCounter::kMediaStreamConstraintsGoogEchoCancellation);
 | 
| +  }
 | 
| +  if (RequestUsesDiscreteConstraint(
 | 
| +          constraints,
 | 
| +          &WebMediaTrackConstraintSet::goog_experimental_echo_cancellation)) {
 | 
| +    counter.Count(
 | 
| +        UseCounter::kMediaStreamConstraintsGoogExperimentalEchoCancellation);
 | 
| +  }
 | 
| +  if (RequestUsesDiscreteConstraint(
 | 
| +          constraints, &WebMediaTrackConstraintSet::goog_auto_gain_control)) {
 | 
| +    counter.Count(UseCounter::kMediaStreamConstraintsGoogAutoGainControl);
 | 
| +  }
 | 
| +  if (RequestUsesDiscreteConstraint(
 | 
| +          constraints,
 | 
| +          &WebMediaTrackConstraintSet::goog_experimental_auto_gain_control)) {
 | 
| +    counter.Count(
 | 
| +        UseCounter::kMediaStreamConstraintsGoogExperimentalAutoGainControl);
 | 
| +  }
 | 
| +  if (RequestUsesDiscreteConstraint(
 | 
| +          constraints, &WebMediaTrackConstraintSet::goog_noise_suppression)) {
 | 
| +    counter.Count(UseCounter::kMediaStreamConstraintsGoogNoiseSuppression);
 | 
| +  }
 | 
| +  if (RequestUsesDiscreteConstraint(
 | 
| +          constraints, &WebMediaTrackConstraintSet::goog_highpass_filter)) {
 | 
| +    counter.Count(UseCounter::kMediaStreamConstraintsGoogHighpassFilter);
 | 
| +  }
 | 
| +  if (RequestUsesDiscreteConstraint(
 | 
| +          constraints,
 | 
| +          &WebMediaTrackConstraintSet::goog_typing_noise_detection)) {
 | 
| +    counter.Count(UseCounter::kMediaStreamConstraintsGoogTypingNoiseDetection);
 | 
| +  }
 | 
| +  if (RequestUsesDiscreteConstraint(
 | 
| +          constraints,
 | 
| +          &WebMediaTrackConstraintSet::goog_experimental_noise_suppression)) {
 | 
| +    counter.Count(
 | 
| +        UseCounter::kMediaStreamConstraintsGoogExperimentalNoiseSuppression);
 | 
| +  }
 | 
| +  if (RequestUsesDiscreteConstraint(
 | 
| +          constraints, &WebMediaTrackConstraintSet::goog_beamforming)) {
 | 
| +    counter.Count(UseCounter::kMediaStreamConstraintsGoogBeamforming);
 | 
| +  }
 | 
| +  if (RequestUsesDiscreteConstraint(
 | 
| +          constraints, &WebMediaTrackConstraintSet::goog_array_geometry)) {
 | 
| +    counter.Count(UseCounter::kMediaStreamConstraintsGoogArrayGeometry);
 | 
| +  }
 | 
| +  if (RequestUsesDiscreteConstraint(
 | 
| +          constraints, &WebMediaTrackConstraintSet::goog_audio_mirroring)) {
 | 
| +    counter.Count(UseCounter::kMediaStreamConstraintsGoogAudioMirroring);
 | 
| +  }
 | 
| +  if (RequestUsesDiscreteConstraint(
 | 
| +          constraints,
 | 
| +          &WebMediaTrackConstraintSet::goog_da_echo_cancellation)) {
 | 
| +    counter.Count(UseCounter::kMediaStreamConstraintsGoogDAEchoCancellation);
 | 
| +  }
 | 
| +
 | 
| +  UseCounter::Count(context, UseCounter::kMediaStreamConstraintsAudio);
 | 
| +  if (counter.IsUnconstrained()) {
 | 
| +    UseCounter::Count(context,
 | 
| +                      UseCounter::kMediaStreamConstraintsAudioUnconstrained);
 | 
| +  }
 | 
| +}
 | 
| +
 | 
| +void CountVideoConstraintUses(ExecutionContext* context,
 | 
| +                              const WebMediaConstraints& constraints) {
 | 
| +  FeatureCounter counter(context);
 | 
| +  if (RequestUsesNumericConstraint(constraints,
 | 
| +                                   &WebMediaTrackConstraintSet::width)) {
 | 
| +    counter.Count(UseCounter::kMediaStreamConstraintsWidth);
 | 
| +  }
 | 
| +  if (RequestUsesNumericConstraint(constraints,
 | 
| +                                   &WebMediaTrackConstraintSet::height)) {
 | 
| +    counter.Count(UseCounter::kMediaStreamConstraintsHeight);
 | 
| +  }
 | 
| +  if (RequestUsesNumericConstraint(constraints,
 | 
| +                                   &WebMediaTrackConstraintSet::aspect_ratio)) {
 | 
| +    counter.Count(UseCounter::kMediaStreamConstraintsAspectRatio);
 | 
| +  }
 | 
| +  if (RequestUsesNumericConstraint(constraints,
 | 
| +                                   &WebMediaTrackConstraintSet::frame_rate)) {
 | 
| +    counter.Count(UseCounter::kMediaStreamConstraintsFrameRate);
 | 
| +  }
 | 
| +  if (RequestUsesDiscreteConstraint(constraints,
 | 
| +                                    &WebMediaTrackConstraintSet::facing_mode)) {
 | 
| +    counter.Count(UseCounter::kMediaStreamConstraintsFacingMode);
 | 
| +  }
 | 
| +  if (RequestUsesDiscreteConstraint(constraints,
 | 
| +                                    &WebMediaTrackConstraintSet::device_id)) {
 | 
| +    counter.Count(UseCounter::kMediaStreamConstraintsDeviceIdVideo);
 | 
| +  }
 | 
| +  if (RequestUsesDiscreteConstraint(constraints,
 | 
| +                                    &WebMediaTrackConstraintSet::group_id)) {
 | 
| +    counter.Count(UseCounter::kMediaStreamConstraintsGroupIdVideo);
 | 
| +  }
 | 
| +  if (RequestUsesDiscreteConstraint(constraints,
 | 
| +                                    &WebMediaTrackConstraintSet::video_kind)) {
 | 
| +    counter.Count(UseCounter::kMediaStreamConstraintsVideoKind);
 | 
| +  }
 | 
| +  if (RequestUsesNumericConstraint(constraints,
 | 
| +                                   &WebMediaTrackConstraintSet::depth_near)) {
 | 
| +    counter.Count(UseCounter::kMediaStreamConstraintsDepthNear);
 | 
| +  }
 | 
| +  if (RequestUsesNumericConstraint(constraints,
 | 
| +                                   &WebMediaTrackConstraintSet::depth_far)) {
 | 
| +    counter.Count(UseCounter::kMediaStreamConstraintsDepthFar);
 | 
| +  }
 | 
| +  if (RequestUsesNumericConstraint(
 | 
| +          constraints, &WebMediaTrackConstraintSet::focal_length_x)) {
 | 
| +    counter.Count(UseCounter::kMediaStreamConstraintsFocalLengthX);
 | 
| +  }
 | 
| +  if (RequestUsesNumericConstraint(
 | 
| +          constraints, &WebMediaTrackConstraintSet::focal_length_y)) {
 | 
| +    counter.Count(UseCounter::kMediaStreamConstraintsFocalLengthY);
 | 
| +  }
 | 
| +  if (RequestUsesDiscreteConstraint(
 | 
| +          constraints, &WebMediaTrackConstraintSet::media_stream_source)) {
 | 
| +    counter.Count(UseCounter::kMediaStreamConstraintsMediaStreamSourceVideo);
 | 
| +  }
 | 
| +  if (RequestUsesDiscreteConstraint(
 | 
| +          constraints, &WebMediaTrackConstraintSet::goog_noise_reduction)) {
 | 
| +    counter.Count(UseCounter::kMediaStreamConstraintsGoogNoiseReduction);
 | 
| +  }
 | 
| +  if (RequestUsesNumericConstraint(
 | 
| +          constraints,
 | 
| +          &WebMediaTrackConstraintSet::goog_power_line_frequency)) {
 | 
| +    counter.Count(UseCounter::kMediaStreamConstraintsGoogPowerLineFrequency);
 | 
| +  }
 | 
| +
 | 
| +  UseCounter::Count(context, UseCounter::kMediaStreamConstraintsVideo);
 | 
| +  if (counter.IsUnconstrained()) {
 | 
| +    UseCounter::Count(context,
 | 
| +                      UseCounter::kMediaStreamConstraintsVideoUnconstrained);
 | 
| +  }
 | 
| +}
 | 
| +
 | 
| +WebMediaConstraints ParseOptions(ExecutionContext* context,
 | 
| +                                 const BooleanOrMediaTrackConstraints& options,
 | 
| +                                 MediaErrorState& error_state) {
 | 
|    WebMediaConstraints constraints;
 | 
|  
 | 
|    Dictionary constraints_dictionary;
 | 
| @@ -71,6 +322,8 @@ static WebMediaConstraints ParseOptions(
 | 
|    return constraints;
 | 
|  }
 | 
|  
 | 
| +}  // namespace
 | 
| +
 | 
|  UserMediaRequest* UserMediaRequest::Create(
 | 
|      ExecutionContext* context,
 | 
|      UserMediaController* controller,
 | 
| @@ -94,6 +347,11 @@ UserMediaRequest* UserMediaRequest::Create(
 | 
|      return nullptr;
 | 
|    }
 | 
|  
 | 
| +  if (!audio.IsNull())
 | 
| +    CountAudioConstraintUses(context, audio);
 | 
| +  if (!video.IsNull())
 | 
| +    CountVideoConstraintUses(context, video);
 | 
| +
 | 
|    return new UserMediaRequest(context, controller, audio, video,
 | 
|                                success_callback, error_callback);
 | 
|  }
 | 
| 
 |