Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(510)

Side by Side Diff: third_party/WebKit/Source/modules/mediastream/MediaConstraintsImpl.cpp

Issue 1581103002: Use new-style constraints for device selection. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@constraints-errors
Patch Set: More constraints from Libjingle Created 4 years, 11 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
1 /* 1 /*
2 * Copyright (C) 2012 Google Inc. All rights reserved. 2 * Copyright (C) 2012 Google Inc. All rights reserved.
3 * 3 *
4 * Redistribution and use in source and binary forms, with or without 4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions 5 * modification, are permitted provided that the following conditions
6 * are met: 6 * are met:
7 * 7 *
8 * 1. Redistributions of source code must retain the above copyright 8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer. 9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright 10 * 2. Redistributions in binary form must reproduce the above copyright
(...skipping 44 matching lines...) Expand 10 before | Expand all | Expand 10 after
55 const char kMaxAspectRatio[] = "maxAspectRatio"; 55 const char kMaxAspectRatio[] = "maxAspectRatio";
56 const char kMaxWidth[] = "maxWidth"; 56 const char kMaxWidth[] = "maxWidth";
57 const char kMinWidth[] = "minWidth"; 57 const char kMinWidth[] = "minWidth";
58 const char kMaxHeight[] = "maxHeight"; 58 const char kMaxHeight[] = "maxHeight";
59 const char kMinHeight[] = "minHeight"; 59 const char kMinHeight[] = "minHeight";
60 const char kMaxFrameRate[] = "maxFrameRate"; 60 const char kMaxFrameRate[] = "maxFrameRate";
61 const char kMinFrameRate[] = "minFrameRate"; 61 const char kMinFrameRate[] = "minFrameRate";
62 // From content/common/media/media_stream_options.cc 62 // From content/common/media/media_stream_options.cc
63 const char kMediaStreamSource[] = "chromeMediaSource"; 63 const char kMediaStreamSource[] = "chromeMediaSource";
64 const char kMediaStreamSourceId[] = "chromeMediaSourceId"; // mapped to deviceId 64 const char kMediaStreamSourceId[] = "chromeMediaSourceId"; // mapped to deviceId
65 const char kMediaStreamSourceInfoId[] = "sourceId"; // mapped to deviceId
65 const char kMediaStreamRenderToAssociatedSink[] = "chromeRenderToAssociatedSink" ; 66 const char kMediaStreamRenderToAssociatedSink[] = "chromeRenderToAssociatedSink" ;
66 // RenderToAssociatedSink will be going away in M50-M60 some time. 67 // RenderToAssociatedSink will be going away in M50-M60 some time.
67 const char kMediaStreamAudioHotword[] = "googHotword"; 68 const char kMediaStreamAudioHotword[] = "googHotword";
68 // From content/renderer/media/media_stream_audio_processor_options.cc 69 // From content/renderer/media/media_stream_audio_processor_options.cc
69 const char kEchoCancellation[] = "echoCancellation"; 70 const char kEchoCancellation[] = "echoCancellation";
70 const char kGoogEchoCancellation[] = "googEchoCancellation"; 71 const char kGoogEchoCancellation[] = "googEchoCancellation";
71 const char kGoogExperimentalEchoCancellation[] = "googEchoCancellation2"; 72 const char kGoogExperimentalEchoCancellation[] = "googEchoCancellation2";
72 const char kGoogAutoGainControl[] = "googAutoGainControl"; 73 const char kGoogAutoGainControl[] = "googAutoGainControl";
73 const char kGoogExperimentalAutoGainControl[] = "googAutoGainControl2"; 74 const char kGoogExperimentalAutoGainControl[] = "googAutoGainControl2";
74 const char kGoogNoiseSuppression[] = "googNoiseSuppression"; 75 const char kGoogNoiseSuppression[] = "googNoiseSuppression";
75 const char kGoogExperimentalNoiseSuppression[] = "googNoiseSuppression2"; 76 const char kGoogExperimentalNoiseSuppression[] = "googNoiseSuppression2";
76 const char kGoogBeamforming[] = "googBeamforming"; 77 const char kGoogBeamforming[] = "googBeamforming";
77 const char kGoogArrayGeometry[] = "googArrayGeometry"; 78 const char kGoogArrayGeometry[] = "googArrayGeometry";
78 const char kGoogHighpassFilter[] = "googHighpassFilter"; 79 const char kGoogHighpassFilter[] = "googHighpassFilter";
79 const char kGoogTypingNoiseDetection[] = "googTypingNoiseDetection"; 80 const char kGoogTypingNoiseDetection[] = "googTypingNoiseDetection";
80 const char kGoogAudioMirroring[] = "googAudioMirroring"; 81 const char kGoogAudioMirroring[] = "googAudioMirroring";
81 82
83 // From third_party/libjingle/source/talk/app/webrtc/mediaconstraintsinterface.c c
84 // Audio constraints.
85 // const char kExtendedFilterEchoCancellation[] = "googEchoCancellation2"; // du plicate k-name
86 const char kDAEchoCancellation[] = "googDAEchoCancellation";
87 // const char kNoiseSuppression[] = "googNoiseSuppression"; // duplicate k-name
88 // const char kExperimentalNoiseSuppression[] = "googNoiseSuppression2"; // dupl icate k-name
89 // const char kHighpassFilter[] = "googHighpassFilter"; // duplicate k-name
90 // const char kTypingNoiseDetection[] = "googTypingNoiseDetection"; // duplicate k-name
91 // const char kAudioMirroring[] = "googAudioMirroring"; // duplicate k-name
92 const char kAecDump[] = "audioDebugRecording";
93
94 // Google-specific constraint keys for a local video source (getUserMedia).
95 const char kNoiseReduction[] = "googNoiseReduction";
96
97 // Constraint keys for CreateOffer / CreateAnswer defined in W3C specification.
98 const char kOfferToReceiveAudio[] = "OfferToReceiveAudio";
99 const char kOfferToReceiveVideo[] = "OfferToReceiveVideo";
100 const char kVoiceActivityDetection[] = "VoiceActivityDetection";
101 const char kIceRestart[] = "IceRestart";
102 // Google specific constraint for BUNDLE enable/disable.
103 const char kUseRtpMux[] = "googUseRtpMUX";
104 // Below constraints should be used during PeerConnection construction.
105 const char kEnableDtlsSrtp[] = "DtlsSrtpKeyAgreement";
106 const char kEnableRtpDataChannels[] = "RtpDataChannels";
107 // Google-specific constraint keys.
108 const char kEnableDscp[] = "googDscp";
109 const char kEnableIPv6[] = "googIPv6";
110 const char kEnableVideoSuspendBelowMinBitrate[] = "googSuspendBelowMinBitrate";
111 const char kNumUnsignalledRecvStreams[] = "googNumUnsignalledRecvStreams";
112 const char kCombinedAudioVideoBwe[] = "googCombinedAudioVideoBwe";
113 const char kScreencastMinBitrate[] = "googScreencastMinBitrate";
114 const char kCpuOveruseDetection[] = "googCpuOveruseDetection";
115 const char kCpuUnderuseThreshold[] = "googCpuUnderuseThreshold";
116 const char kCpuOveruseThreshold[] = "googCpuOveruseThreshold";
117 const char kCpuUnderuseEncodeRsdThreshold[] = "googCpuUnderuseEncodeRsdThreshold ";
118 const char kCpuOveruseEncodeRsdThreshold[] = "googCpuOveruseEncodeRsdThreshold";
119 const char kCpuOveruseEncodeUsage[] = "googCpuOveruseEncodeUsage";
120 const char kHighStartBitrate[] = "googHighStartBitrate";
121 const char kPayloadPadding[] = "googPayloadPadding";
122 // End of names from libjingle
123
82 // Names used for testing. 124 // Names used for testing.
83 const char kTestConstraint1[] = "valid_and_supported_1"; 125 const char kTestConstraint1[] = "valid_and_supported_1";
84 const char kTestConstraint2[] = "valid_and_supported_2"; 126 const char kTestConstraint2[] = "valid_and_supported_2";
85 127
86 static bool parseMandatoryConstraintsDictionary(const Dictionary& mandatoryConst raintsDictionary, WebVector<WebMediaConstraint>& mandatory) 128 static bool parseMandatoryConstraintsDictionary(const Dictionary& mandatoryConst raintsDictionary, WebVector<WebMediaConstraint>& mandatory)
87 { 129 {
88 Vector<WebMediaConstraint> mandatoryConstraintsVector; 130 Vector<WebMediaConstraint> mandatoryConstraintsVector;
89 HashMap<String, String> mandatoryConstraintsHashMap; 131 HashMap<String, String> mandatoryConstraintsHashMap;
90 bool ok = mandatoryConstraintsDictionary.getOwnPropertiesAsStringHashMap(man datoryConstraintsHashMap); 132 bool ok = mandatoryConstraintsDictionary.getOwnPropertiesAsStringHashMap(man datoryConstraintsHashMap);
91 if (!ok) 133 if (!ok)
(...skipping 102 matching lines...) Expand 10 before | Expand all | Expand 10 after
194 } 236 }
195 return true; 237 return true;
196 } 238 }
197 239
198 static bool toBoolean(const WebString& asWebString) 240 static bool toBoolean(const WebString& asWebString)
199 { 241 {
200 return asWebString.equals("true") || asWebString.equals("True"); 242 return asWebString.equals("true") || asWebString.equals("True");
201 // TODO(hta): Verify this against code that currently parses bool constraint s. 243 // TODO(hta): Verify this against code that currently parses bool constraint s.
202 } 244 }
203 245
204 static void parseOldStyleNames(const WebVector<WebMediaConstraint>& oldNames, We bMediaTrackConstraintSet result, MediaErrorState& errorState) 246 static void parseOldStyleNames(const WebVector<WebMediaConstraint>& oldNames, We bMediaTrackConstraintSet& result, MediaErrorState& errorState)
205 { 247 {
206 for (const WebMediaConstraint& constraint : oldNames) { 248 for (const WebMediaConstraint& constraint : oldNames) {
207 if (constraint.m_name.equals(kMinAspectRatio)) { 249 if (constraint.m_name.equals(kMinAspectRatio)) {
208 result.aspectRatio.setMin(atof(constraint.m_value.utf8().c_str())); 250 result.aspectRatio.setMin(atof(constraint.m_value.utf8().c_str()));
209 } else if (constraint.m_name.equals(kMaxAspectRatio)) { 251 } else if (constraint.m_name.equals(kMaxAspectRatio)) {
210 result.aspectRatio.setMax(atof(constraint.m_value.utf8().c_str())); 252 result.aspectRatio.setMax(atof(constraint.m_value.utf8().c_str()));
211 } else if (constraint.m_name.equals(kMaxWidth)) { 253 } else if (constraint.m_name.equals(kMaxWidth)) {
212 result.width.setMax(atoi(constraint.m_value.utf8().c_str())); 254 result.width.setMax(atoi(constraint.m_value.utf8().c_str()));
213 } else if (constraint.m_name.equals(kMinWidth)) { 255 } else if (constraint.m_name.equals(kMinWidth)) {
214 result.width.setMin(atoi(constraint.m_value.utf8().c_str())); 256 result.width.setMin(atoi(constraint.m_value.utf8().c_str()));
215 } else if (constraint.m_name.equals(kMaxHeight)) { 257 } else if (constraint.m_name.equals(kMaxHeight)) {
216 result.height.setMax(atoi(constraint.m_value.utf8().c_str())); 258 result.height.setMax(atoi(constraint.m_value.utf8().c_str()));
217 } else if (constraint.m_name.equals(kMinHeight)) { 259 } else if (constraint.m_name.equals(kMinHeight)) {
218 result.height.setMin(atoi(constraint.m_value.utf8().c_str())); 260 result.height.setMin(atoi(constraint.m_value.utf8().c_str()));
219 } else if (constraint.m_name.equals(kMinFrameRate)) { 261 } else if (constraint.m_name.equals(kMinFrameRate)) {
220 result.frameRate.setMin(atof(constraint.m_value.utf8().c_str())); 262 result.frameRate.setMin(atof(constraint.m_value.utf8().c_str()));
221 } else if (constraint.m_name.equals(kMaxFrameRate)) { 263 } else if (constraint.m_name.equals(kMaxFrameRate)) {
222 result.frameRate.setMax(atof(constraint.m_value.utf8().c_str())); 264 result.frameRate.setMax(atof(constraint.m_value.utf8().c_str()));
223 } else if (constraint.m_name.equals(kEchoCancellation)) { 265 } else if (constraint.m_name.equals(kEchoCancellation)) {
224 result.echoCancellation.setExact(toBoolean(constraint.m_value)); 266 result.echoCancellation.setExact(toBoolean(constraint.m_value));
225 } else if (constraint.m_name.equals(kMediaStreamSource)) { 267 } else if (constraint.m_name.equals(kMediaStreamSource)) {
226 // TODO(hta): This has only a few legal values. Should be 268 // TODO(hta): This has only a few legal values. Should be
227 // represented as an enum, and cause type errors. 269 // represented as an enum, and cause type errors.
228 // https://crbug.com/576582 270 // https://crbug.com/576582
229 result.mediaStreamSource.setExact(constraint.m_value); 271 result.mediaStreamSource.setExact(constraint.m_value);
230 } else if (constraint.m_name.equals(kMediaStreamSourceId)) { 272 } else if (constraint.m_name.equals(kMediaStreamSourceId)
273 || constraint.m_name.equals(kMediaStreamSourceInfoId)) {
274 WTF_LOG(Media, "Copying a device ID");
tommi (sloooow) - chröme 2016/01/14 15:31:27 remove?
hta - Chromium 2016/01/17 12:41:41 Done.
231 result.deviceId.setExact(constraint.m_value); 275 result.deviceId.setExact(constraint.m_value);
232 } else if (constraint.m_name.equals(kMediaStreamRenderToAssociatedSink)) { 276 } else if (constraint.m_name.equals(kMediaStreamRenderToAssociatedSink)) {
233 // TODO(hta): This is a boolean represented as string. 277 // TODO(hta): This is a boolean represented as string.
234 // Should give TypeError when it's not parseable. 278 // Should give TypeError when it's not parseable.
235 // https://crbug.com/576582 279 // https://crbug.com/576582
236 result.renderToAssociatedSink.setExact(toBoolean(constraint.m_value) ); 280 result.renderToAssociatedSink.setExact(toBoolean(constraint.m_value) );
237 } else if (constraint.m_name.equals(kMediaStreamAudioHotword)) { 281 } else if (constraint.m_name.equals(kMediaStreamAudioHotword)) {
238 result.hotwordEnabled.setExact(toBoolean(constraint.m_value)); 282 result.hotwordEnabled.setExact(toBoolean(constraint.m_value));
239 } else if (constraint.m_name.equals(kGoogEchoCancellation)) { 283 } else if (constraint.m_name.equals(kGoogEchoCancellation)) {
240 result.googEchoCancellation.setExact(toBoolean(constraint.m_value)); 284 result.googEchoCancellation.setExact(toBoolean(constraint.m_value));
(...skipping 10 matching lines...) Expand all
251 } else if (constraint.m_name.equals(kGoogBeamforming)) { 295 } else if (constraint.m_name.equals(kGoogBeamforming)) {
252 result.googBeamforming.setExact(toBoolean(constraint.m_value)); 296 result.googBeamforming.setExact(toBoolean(constraint.m_value));
253 } else if (constraint.m_name.equals(kGoogArrayGeometry)) { 297 } else if (constraint.m_name.equals(kGoogArrayGeometry)) {
254 result.googArrayGeometry.setExact(constraint.m_value); 298 result.googArrayGeometry.setExact(constraint.m_value);
255 } else if (constraint.m_name.equals(kGoogHighpassFilter)) { 299 } else if (constraint.m_name.equals(kGoogHighpassFilter)) {
256 result.googHighpassFilter.setExact(toBoolean(constraint.m_value)); 300 result.googHighpassFilter.setExact(toBoolean(constraint.m_value));
257 } else if (constraint.m_name.equals(kGoogTypingNoiseDetection)) { 301 } else if (constraint.m_name.equals(kGoogTypingNoiseDetection)) {
258 result.googTypingNoiseDetection.setExact(toBoolean(constraint.m_valu e)); 302 result.googTypingNoiseDetection.setExact(toBoolean(constraint.m_valu e));
259 } else if (constraint.m_name.equals(kGoogAudioMirroring)) { 303 } else if (constraint.m_name.equals(kGoogAudioMirroring)) {
260 result.googAudioMirroring.setExact(toBoolean(constraint.m_value)); 304 result.googAudioMirroring.setExact(toBoolean(constraint.m_value));
305 } else if (constraint.m_name.equals(kDAEchoCancellation)) {
306 result.googDAEchoCancellation.setExact(toBoolean(constraint.m_value) );
307 } else if (constraint.m_name.equals(kAecDump)) {
308 result.googAecDump.setExact(toBoolean(constraint.m_value));
309 } else if (constraint.m_name.equals(kNoiseReduction)) {
310 result.googNoiseReduction.setExact(toBoolean(constraint.m_value));
311 } else if (constraint.m_name.equals(kOfferToReceiveAudio)) {
312 result.offerToReceiveAudio.setExact(constraint.m_value);
313 } else if (constraint.m_name.equals(kOfferToReceiveVideo)) {
314 result.offerToReceiveVideo.setExact(constraint.m_value);
315 } else if (constraint.m_name.equals(kVoiceActivityDetection)) {
316 result.voiceActivityDetection.setExact(toBoolean(constraint.m_value) );
317 } else if (constraint.m_name.equals(kIceRestart)) {
318 result.iceRestart.setExact(toBoolean(constraint.m_value));
319 } else if (constraint.m_name.equals(kUseRtpMux)) {
320 result.googUseRtpMux.setExact(toBoolean(constraint.m_value));
321 } else if (constraint.m_name.equals(kEnableDtlsSrtp)) {
322 result.enableDtlsSrtp.setExact(toBoolean(constraint.m_value));
323 } else if (constraint.m_name.equals(kEnableRtpDataChannels)) {
324 result.enableRtpDataChannels.setExact(toBoolean(constraint.m_value)) ;
325 } else if (constraint.m_name.equals(kEnableDscp)) {
326 result.enableDscp.setExact(toBoolean(constraint.m_value));
327 } else if (constraint.m_name.equals(kEnableIPv6)) {
328 result.enableIPv6.setExact(toBoolean(constraint.m_value));
329 } else if (constraint.m_name.equals(kEnableVideoSuspendBelowMinBitrate)) {
330 result.googEnableVideoSuspendBelowMinBitrate.setExact(toBoolean(cons traint.m_value));
331 } else if (constraint.m_name.equals(kNumUnsignalledRecvStreams)) {
332 result.googNumUnsignalledRecvStreams.setExact(atoi(constraint.m_valu e.utf8().c_str()));
333 } else if (constraint.m_name.equals(kCombinedAudioVideoBwe)) {
334 result.googCombinedAudioVideoBwe.setExact(toBoolean(constraint.m_val ue));
335 } else if (constraint.m_name.equals(kScreencastMinBitrate)) {
336 result.googScreencastMinBitrate.setExact(atoi(constraint.m_value.utf 8().c_str()));
337 } else if (constraint.m_name.equals(kCpuOveruseDetection)) {
338 result.googCpuOveruseDetection.setExact(toBoolean(constraint.m_value ));
339 } else if (constraint.m_name.equals(kCpuUnderuseThreshold)) {
340 result.googCpuUnderuseThreshold.setExact(atoi(constraint.m_value.utf 8().c_str()));
341 } else if (constraint.m_name.equals(kCpuOveruseThreshold)) {
342 result.googCpuOveruseThreshold.setExact(atoi(constraint.m_value.utf8 ().c_str()));
343 } else if (constraint.m_name.equals(kCpuUnderuseEncodeRsdThreshold)) {
344 result.googCpuUnderuseEncodeRsdThreshold.setExact(atoi(constraint.m_ value.utf8().c_str()));
345 } else if (constraint.m_name.equals(kCpuOveruseEncodeRsdThreshold)) {
346 result.googCpuOveruseEncodeRsdThreshold.setExact(atoi(constraint.m_v alue.utf8().c_str()));
347 } else if (constraint.m_name.equals(kCpuOveruseEncodeUsage)) {
348 result.googCpuOveruseEncodeUsage.setExact(toBoolean(constraint.m_val ue));
349 } else if (constraint.m_name.equals(kHighStartBitrate)) {
350 result.googHighStartBitrate.setExact(atoi(constraint.m_value.utf8(). c_str()));
351 } else if (constraint.m_name.equals(kPayloadPadding)) {
352 result.googPayloadPadding.setExact(toBoolean(constraint.m_value));
261 } else if (constraint.m_name.equals(kTestConstraint1) 353 } else if (constraint.m_name.equals(kTestConstraint1)
262 || constraint.m_name.equals(kTestConstraint2)) { 354 || constraint.m_name.equals(kTestConstraint2)) {
263 // These constraints are only for testing parsing. Ignore them. 355 // These constraints are only for testing parsing. Ignore them.
264 } else { 356 } else {
265 // TODO(hta): UMA stats for unknown constraints passed. 357 // TODO(hta): UMA stats for unknown constraints passed.
266 // https://crbug.com/576613 358 // https://crbug.com/576613
267 WTF_LOG(Media, "Unknown constraint name detected"); 359 WTF_LOG(Media, "Unknown constraint name detected");
268 errorState.throwConstraintError("Unknown name of constraint detected ", constraint.m_name); 360 errorState.throwConstraintError("Unknown name of constraint detected ", constraint.m_name);
269 } 361 }
270 } 362 }
271 } 363 }
272 364
273 static WebMediaConstraints createFromNamedConstraints(WebVector<WebMediaConstrai nt>& mandatory, const WebVector<WebMediaConstraint>& optional, MediaErrorState& errorState) 365 static WebMediaConstraints createFromNamedConstraints(WebVector<WebMediaConstrai nt>& mandatory, const WebVector<WebMediaConstraint>& optional, MediaErrorState& errorState)
274 { 366 {
275 WebMediaTrackConstraintSet basic; 367 WebMediaTrackConstraintSet basic;
276 WebMediaTrackConstraintSet advanced; 368 WebMediaTrackConstraintSet advanced;
277 WebMediaConstraints constraints; 369 WebMediaConstraints constraints;
278 if (RuntimeEnabledFeatures::mediaConstraintsEnabled()) { 370 parseOldStyleNames(mandatory, basic, errorState);
279 parseOldStyleNames(mandatory, basic, errorState); 371 if (errorState.hadException())
280 if (errorState.hadException()) 372 return constraints;
281 return constraints; 373 // We ignore errors in optional constraints.
282 // We ignore errors in optional constraints. 374 MediaErrorState ignoredErrorState;
283 MediaErrorState ignoredErrorState; 375 parseOldStyleNames(optional, advanced, ignoredErrorState);
284 parseOldStyleNames(optional, advanced, ignoredErrorState);
285 }
286 WebVector<WebMediaTrackConstraintSet> advancedVector(&advanced, 1); 376 WebVector<WebMediaTrackConstraintSet> advancedVector(&advanced, 1);
287 // Use the 4-argument initializer until Chrome has been converted. 377 // Use the 4-argument initializer until Chrome has been converted.
288 constraints.initialize(optional, mandatory, basic, advancedVector); 378 constraints.initialize(optional, mandatory, basic, advancedVector);
289 return constraints; 379 return constraints;
290 } 380 }
291 381
292 // Deprecated. 382 // Deprecated.
293 WebMediaConstraints create(const Dictionary& constraintsDictionary, MediaErrorSt ate& errorState) 383 WebMediaConstraints create(const Dictionary& constraintsDictionary, MediaErrorSt ate& errorState)
294 { 384 {
295 WebVector<WebMediaConstraint> optional; 385 WebVector<WebMediaConstraint> optional;
(...skipping 130 matching lines...) Expand 10 before | Expand all | Expand 10 after
426 516
427 WebMediaConstraints create() 517 WebMediaConstraints create()
428 { 518 {
429 WebMediaConstraints constraints; 519 WebMediaConstraints constraints;
430 constraints.initialize(); 520 constraints.initialize();
431 return constraints; 521 return constraints;
432 } 522 }
433 523
434 } // namespace MediaConstraintsImpl 524 } // namespace MediaConstraintsImpl
435 } // namespace blink 525 } // namespace blink
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698