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

Side by Side Diff: content/renderer/media/user_media_client_impl.cc

Issue 2696443002: Reland of Use spec-compliant algorithm to select video devices in getUserMedia. (Closed)
Patch Set: Address boliu's comments Created 3 years, 10 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 // Copyright (c) 2012 The Chromium Authors. All rights reserved. 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include "content/renderer/media/user_media_client_impl.h" 5 #include "content/renderer/media/user_media_client_impl.h"
6 6
7 #include <stddef.h> 7 #include <stddef.h>
8 8
9 #include <algorithm> 9 #include <algorithm>
10 #include <utility> 10 #include <utility>
11 11
12 #include "base/hash.h" 12 #include "base/hash.h"
13 #include "base/location.h" 13 #include "base/location.h"
14 #include "base/logging.h" 14 #include "base/logging.h"
15 #include "base/memory/ptr_util.h" 15 #include "base/memory/ptr_util.h"
16 #include "base/single_thread_task_runner.h" 16 #include "base/single_thread_task_runner.h"
17 #include "base/strings/string_number_conversions.h" 17 #include "base/strings/string_number_conversions.h"
18 #include "base/strings/string_util.h" 18 #include "base/strings/string_util.h"
19 #include "base/strings/stringprintf.h" 19 #include "base/strings/stringprintf.h"
20 #include "base/strings/utf_string_conversions.h" 20 #include "base/strings/utf_string_conversions.h"
21 #include "base/task_runner.h"
22 #include "base/task_runner_util.h"
21 #include "base/threading/thread_task_runner_handle.h" 23 #include "base/threading/thread_task_runner_handle.h"
22 #include "build/build_config.h" 24 #include "build/build_config.h"
23 #include "content/public/renderer/render_frame.h" 25 #include "content/public/renderer/render_frame.h"
24 #include "content/renderer/media/local_media_stream_audio_source.h" 26 #include "content/renderer/media/local_media_stream_audio_source.h"
25 #include "content/renderer/media/media_stream.h" 27 #include "content/renderer/media/media_stream.h"
26 #include "content/renderer/media/media_stream_constraints_util.h" 28 #include "content/renderer/media/media_stream_constraints_util.h"
29 #include "content/renderer/media/media_stream_constraints_util_video_source.h"
27 #include "content/renderer/media/media_stream_dispatcher.h" 30 #include "content/renderer/media/media_stream_dispatcher.h"
28 #include "content/renderer/media/media_stream_video_capturer_source.h" 31 #include "content/renderer/media/media_stream_video_capturer_source.h"
29 #include "content/renderer/media/media_stream_video_track.h" 32 #include "content/renderer/media/media_stream_video_track.h"
30 #include "content/renderer/media/peer_connection_tracker.h" 33 #include "content/renderer/media/peer_connection_tracker.h"
31 #include "content/renderer/media/webrtc/processed_local_audio_source.h" 34 #include "content/renderer/media/webrtc/processed_local_audio_source.h"
32 #include "content/renderer/media/webrtc/webrtc_video_capturer_adapter.h" 35 #include "content/renderer/media/webrtc/webrtc_video_capturer_adapter.h"
33 #include "content/renderer/media/webrtc_logging.h" 36 #include "content/renderer/media/webrtc_logging.h"
34 #include "content/renderer/media/webrtc_uma_histograms.h" 37 #include "content/renderer/media/webrtc_uma_histograms.h"
35 #include "content/renderer/render_thread_impl.h" 38 #include "content/renderer/render_thread_impl.h"
39 #include "media/capture/video_capture_types.h"
36 #include "third_party/WebKit/public/platform/URLConversion.h" 40 #include "third_party/WebKit/public/platform/URLConversion.h"
37 #include "third_party/WebKit/public/platform/WebMediaConstraints.h" 41 #include "third_party/WebKit/public/platform/WebMediaConstraints.h"
38 #include "third_party/WebKit/public/platform/WebMediaDeviceInfo.h" 42 #include "third_party/WebKit/public/platform/WebMediaDeviceInfo.h"
39 #include "third_party/WebKit/public/platform/WebMediaStreamTrack.h" 43 #include "third_party/WebKit/public/platform/WebMediaStreamTrack.h"
40 #include "third_party/WebKit/public/platform/WebString.h" 44 #include "third_party/WebKit/public/platform/WebString.h"
41 #include "third_party/WebKit/public/web/WebDocument.h" 45 #include "third_party/WebKit/public/web/WebDocument.h"
42 #include "third_party/WebKit/public/web/WebLocalFrame.h" 46 #include "third_party/WebKit/public/web/WebLocalFrame.h"
47 #include "third_party/WebKit/public/web/WebUserGestureIndicator.h"
43 48
44 namespace content { 49 namespace content {
45 namespace { 50 namespace {
46 51
47 void CopyFirstString(const blink::StringConstraint& constraint, 52 void CopyFirstString(const blink::StringConstraint& constraint,
48 std::string* destination) { 53 std::string* destination) {
49 if (!constraint.exact().isEmpty()) 54 if (!constraint.exact().isEmpty())
50 *destination = constraint.exact()[0].utf8(); 55 *destination = constraint.exact()[0].utf8();
51 } 56 }
52 57
(...skipping 154 matching lines...) Expand 10 before | Expand all | Expand 10 after
207 default: 212 default:
208 NOTREACHED(); 213 NOTREACHED();
209 return blink::WebMediaDeviceInfo::MediaDeviceKindAudioInput; 214 return blink::WebMediaDeviceInfo::MediaDeviceKindAudioInput;
210 } 215 }
211 } 216 }
212 217
213 static int g_next_request_id = 0; 218 static int g_next_request_id = 0;
214 219
215 } // namespace 220 } // namespace
216 221
222 struct UserMediaClientImpl::RequestSettings {
223 RequestSettings(bool is_processing_user_gesture, url::Origin security_origin)
224 : enable_automatic_audio_output_device_selection(false),
225 is_processing_user_gesture(is_processing_user_gesture),
226 security_origin(security_origin) {}
227 ~RequestSettings() = default;
228
229 bool enable_automatic_audio_output_device_selection;
230 bool is_processing_user_gesture;
231 url::Origin security_origin;
232 };
233
217 UserMediaClientImpl::UserMediaClientImpl( 234 UserMediaClientImpl::UserMediaClientImpl(
218 RenderFrame* render_frame, 235 RenderFrame* render_frame,
219 PeerConnectionDependencyFactory* dependency_factory, 236 PeerConnectionDependencyFactory* dependency_factory,
220 std::unique_ptr<MediaStreamDispatcher> media_stream_dispatcher) 237 std::unique_ptr<MediaStreamDispatcher> media_stream_dispatcher,
238 const scoped_refptr<base::TaskRunner>& worker_task_runner)
221 : RenderFrameObserver(render_frame), 239 : RenderFrameObserver(render_frame),
222 dependency_factory_(dependency_factory), 240 dependency_factory_(dependency_factory),
223 media_stream_dispatcher_(std::move(media_stream_dispatcher)), 241 media_stream_dispatcher_(std::move(media_stream_dispatcher)),
242 worker_task_runner_(worker_task_runner),
224 weak_factory_(this) { 243 weak_factory_(this) {
225 DCHECK(dependency_factory_); 244 DCHECK(dependency_factory_);
226 DCHECK(media_stream_dispatcher_.get()); 245 DCHECK(media_stream_dispatcher_.get());
227 } 246 }
228 247
229 UserMediaClientImpl::~UserMediaClientImpl() { 248 UserMediaClientImpl::~UserMediaClientImpl() {
230 // Force-close all outstanding user media requests and local sources here, 249 // Force-close all outstanding user media requests and local sources here,
231 // before the outstanding WeakPtrs are invalidated, to ensure a clean 250 // before the outstanding WeakPtrs are invalidated, to ensure a clean
232 // shutdown. 251 // shutdown.
233 WillCommitProvisionalLoad(); 252 WillCommitProvisionalLoad();
(...skipping 15 matching lines...) Expand all
249 user_media_request.ownerDocument().frame())); 268 user_media_request.ownerDocument().frame()));
250 269
251 if (RenderThreadImpl::current()) { 270 if (RenderThreadImpl::current()) {
252 RenderThreadImpl::current()->peer_connection_tracker()->TrackGetUserMedia( 271 RenderThreadImpl::current()->peer_connection_tracker()->TrackGetUserMedia(
253 user_media_request); 272 user_media_request);
254 } 273 }
255 274
256 int request_id = g_next_request_id++; 275 int request_id = g_next_request_id++;
257 std::unique_ptr<StreamControls> controls = base::MakeUnique<StreamControls>(); 276 std::unique_ptr<StreamControls> controls = base::MakeUnique<StreamControls>();
258 277
259 bool enable_automatic_output_device_selection = false; 278 // The value returned by isProcessingUserGesture() is used by the browser to
260 bool request_audio_input_devices = false; 279 // make decisions about the permissions UI. Its value can be lost while
280 // switching threads, so saving its value here.
281 RequestSettings request_settings(
282 blink::WebUserGestureIndicator::isProcessingUserGesture(),
283 static_cast<url::Origin>(user_media_request.getSecurityOrigin()));
261 if (user_media_request.audio()) { 284 if (user_media_request.audio()) {
285 bool request_audio_input_devices = false;
286 // TODO(guidou): Implement spec-compliant device selection for audio. See
287 // http://crbug.com/623104.
262 CopyConstraintsToTrackControls(user_media_request.audioConstraints(), 288 CopyConstraintsToTrackControls(user_media_request.audioConstraints(),
263 &controls->audio, 289 &controls->audio,
264 &request_audio_input_devices); 290 &request_audio_input_devices);
265 CopyHotwordAndLocalEchoToStreamControls( 291 CopyHotwordAndLocalEchoToStreamControls(
266 user_media_request.audioConstraints(), controls.get()); 292 user_media_request.audioConstraints(), controls.get());
267 // Check if this input device should be used to select a matching output 293 // Check if this input device should be used to select a matching output
268 // device for audio rendering. 294 // device for audio rendering.
269 GetConstraintValueAsBoolean( 295 GetConstraintValueAsBoolean(
270 user_media_request.audioConstraints(), 296 user_media_request.audioConstraints(),
271 &blink::WebMediaTrackConstraintSet::renderToAssociatedSink, 297 &blink::WebMediaTrackConstraintSet::renderToAssociatedSink,
272 &enable_automatic_output_device_selection); 298 &request_settings.enable_automatic_audio_output_device_selection);
273 }
274 bool request_video_input_devices = false;
275 if (user_media_request.video()) {
276 CopyConstraintsToTrackControls(user_media_request.videoConstraints(),
277 &controls->video,
278 &request_video_input_devices);
279 }
280 299
281 url::Origin security_origin = user_media_request.getSecurityOrigin(); 300 if (request_audio_input_devices) {
282 if (request_audio_input_devices || request_video_input_devices) { 301 GetMediaDevicesDispatcher()->EnumerateDevices(
283 GetMediaDevicesDispatcher()->EnumerateDevices( 302 true /* audio_input */, false /* video_input */,
284 request_audio_input_devices, request_video_input_devices, 303 false /* audio_output */, request_settings.security_origin,
285 false /* request_audio_output_devices */, security_origin, 304 base::Bind(&UserMediaClientImpl::SelectAudioInputDevice,
286 base::Bind(&UserMediaClientImpl::SelectUserMediaDevice, 305 weak_factory_.GetWeakPtr(), request_id, user_media_request,
287 weak_factory_.GetWeakPtr(), request_id, user_media_request, 306 base::Passed(&controls), request_settings));
288 base::Passed(&controls),
289 enable_automatic_output_device_selection, security_origin));
290 } else {
291 FinalizeRequestUserMedia(
292 request_id, user_media_request, std::move(controls),
293 enable_automatic_output_device_selection, security_origin);
294 }
295 }
296
297 void UserMediaClientImpl::SelectUserMediaDevice(
298 int request_id,
299 const blink::WebUserMediaRequest& user_media_request,
300 std::unique_ptr<StreamControls> controls,
301 bool enable_automatic_output_device_selection,
302 const url::Origin& security_origin,
303 const EnumerationResult& device_enumeration) {
304 DCHECK(CalledOnValidThread());
305
306 if (controls->audio.requested &&
307 IsDeviceSource(controls->audio.stream_source)) {
308 if (!PickDeviceId(user_media_request.audioConstraints(),
309 device_enumeration[MEDIA_DEVICE_TYPE_AUDIO_INPUT],
310 &controls->audio.device_id)) {
311 GetUserMediaRequestFailed(user_media_request, MEDIA_DEVICE_NO_HARDWARE,
312 "");
313 return; 307 return;
314 } 308 }
315 } 309 }
316 310
317 if (controls->video.requested && 311 SetupVideoInput(request_id, user_media_request, std::move(controls),
318 IsDeviceSource(controls->video.stream_source)) { 312 request_settings);
319 if (!PickDeviceId(user_media_request.videoConstraints(), 313 }
320 device_enumeration[MEDIA_DEVICE_TYPE_VIDEO_INPUT], 314
321 &controls->video.device_id)) { 315 void UserMediaClientImpl::SelectAudioInputDevice(
322 GetUserMediaRequestFailed(user_media_request, MEDIA_DEVICE_NO_HARDWARE, 316 int request_id,
323 ""); 317 const blink::WebUserMediaRequest& user_media_request,
318 std::unique_ptr<StreamControls> controls,
319 const RequestSettings& request_settings,
320 const EnumerationResult& device_enumeration) {
321 DCHECK(CalledOnValidThread());
322 DCHECK(controls->audio.requested);
323 DCHECK(IsDeviceSource(controls->audio.stream_source));
324
325 if (!PickDeviceId(user_media_request.audioConstraints(),
326 device_enumeration[MEDIA_DEVICE_TYPE_AUDIO_INPUT],
327 &controls->audio.device_id)) {
328 GetUserMediaRequestFailed(user_media_request, MEDIA_DEVICE_NO_HARDWARE, "");
329 return;
330 }
331
332 SetupVideoInput(request_id, user_media_request, std::move(controls),
333 request_settings);
334 }
335
336 void UserMediaClientImpl::SetupVideoInput(
337 int request_id,
338 const blink::WebUserMediaRequest& user_media_request,
339 std::unique_ptr<StreamControls> controls,
340 const RequestSettings& request_settings) {
341 if (user_media_request.video()) {
342 bool ignore;
343 CopyConstraintsToTrackControls(user_media_request.videoConstraints(),
344 &controls->video, &ignore);
345 if (IsDeviceSource(controls->video.stream_source)) {
346 GetMediaDevicesDispatcher()->GetVideoInputCapabilities(
347 request_settings.security_origin,
348 base::Bind(&UserMediaClientImpl::SelectVideoDeviceSourceSettings,
349 weak_factory_.GetWeakPtr(), request_id, user_media_request,
350 base::Passed(&controls), request_settings));
324 return; 351 return;
325 } 352 }
326 } 353 }
354 FinalizeRequestUserMedia(request_id, user_media_request, std::move(controls),
355 request_settings);
356 }
327 357
358 void UserMediaClientImpl::SelectVideoDeviceSourceSettings(
359 int request_id,
360 const blink::WebUserMediaRequest& user_media_request,
361 std::unique_ptr<StreamControls> controls,
362 const RequestSettings& request_settings,
363 std::vector<::mojom::VideoInputDeviceCapabilitiesPtr>
364 video_input_capabilities) {
365 DCHECK(CalledOnValidThread());
366 DCHECK(controls->video.requested);
367 DCHECK(IsDeviceSource(controls->video.stream_source));
368
369 VideoCaptureCapabilities capabilities;
370 capabilities.device_capabilities = std::move(video_input_capabilities);
371 capabilities.power_line_capabilities = {
372 media::PowerLineFrequency::FREQUENCY_DEFAULT,
373 media::PowerLineFrequency::FREQUENCY_50HZ,
374 media::PowerLineFrequency::FREQUENCY_60HZ};
375
376 base::PostTaskAndReplyWithResult(
377 worker_task_runner_.get(), FROM_HERE,
378 base::Bind(&SelectVideoCaptureSourceSettings, std::move(capabilities),
379 user_media_request.videoConstraints()),
380 base::Bind(&UserMediaClientImpl::FinalizeSelectVideoDeviceSourceSettings,
381 weak_factory_.GetWeakPtr(), request_id, user_media_request,
382 base::Passed(&controls), request_settings));
383 }
384
385 void UserMediaClientImpl::FinalizeSelectVideoDeviceSourceSettings(
386 int request_id,
387 const blink::WebUserMediaRequest& user_media_request,
388 std::unique_ptr<StreamControls> controls,
389 const RequestSettings& request_settings,
390 const VideoCaptureSourceSelectionResult& selection_result) {
391 DCHECK(CalledOnValidThread());
392 // Select video device.
393 if (!selection_result.has_value()) {
394 blink::WebString failed_constraint_name =
395 blink::WebString::fromASCII(selection_result.failed_constraint_name);
396 MediaStreamRequestResult result =
397 failed_constraint_name.isEmpty()
398 ? MEDIA_DEVICE_NO_HARDWARE
399 : MEDIA_DEVICE_CONSTRAINT_NOT_SATISFIED;
400 GetUserMediaRequestFailed(user_media_request, result,
401 failed_constraint_name);
402 return;
403 }
404 controls->video.device_id = selection_result.settings.device_id();
328 FinalizeRequestUserMedia(request_id, user_media_request, std::move(controls), 405 FinalizeRequestUserMedia(request_id, user_media_request, std::move(controls),
329 enable_automatic_output_device_selection, 406 request_settings);
330 security_origin);
331 } 407 }
332 408
333 void UserMediaClientImpl::FinalizeRequestUserMedia( 409 void UserMediaClientImpl::FinalizeRequestUserMedia(
334 int request_id, 410 int request_id,
335 const blink::WebUserMediaRequest& user_media_request, 411 const blink::WebUserMediaRequest& user_media_request,
336 std::unique_ptr<StreamControls> controls, 412 std::unique_ptr<StreamControls> controls,
337 bool enable_automatic_output_device_selection, 413 const RequestSettings& request_settings) {
338 const url::Origin& security_origin) {
339 DCHECK(CalledOnValidThread()); 414 DCHECK(CalledOnValidThread());
340 415
341 WebRtcLogMessage( 416 WebRtcLogMessage(
342 base::StringPrintf("MSI::requestUserMedia. request_id=%d" 417 base::StringPrintf("MSI::requestUserMedia. request_id=%d"
343 ", audio source id=%s" 418 ", audio source id=%s"
344 ", video source id=%s", 419 ", video source id=%s",
345 request_id, controls->audio.device_id.c_str(), 420 request_id, controls->audio.device_id.c_str(),
346 controls->video.device_id.c_str())); 421 controls->video.device_id.c_str()));
347 422
348 user_media_requests_.push_back(std::unique_ptr<UserMediaRequestInfo>( 423 user_media_requests_.push_back(base::MakeUnique<UserMediaRequestInfo>(
349 new UserMediaRequestInfo(request_id, user_media_request, 424 request_id, user_media_request,
350 enable_automatic_output_device_selection))); 425 request_settings.enable_automatic_audio_output_device_selection));
351 426
352 media_stream_dispatcher_->GenerateStream( 427 media_stream_dispatcher_->GenerateStream(
353 request_id, weak_factory_.GetWeakPtr(), *controls, security_origin); 428 request_id, weak_factory_.GetWeakPtr(), *controls,
429 request_settings.security_origin,
430 request_settings.is_processing_user_gesture);
354 } 431 }
355 432
356 void UserMediaClientImpl::cancelUserMediaRequest( 433 void UserMediaClientImpl::cancelUserMediaRequest(
357 const blink::WebUserMediaRequest& user_media_request) { 434 const blink::WebUserMediaRequest& user_media_request) {
358 DCHECK(CalledOnValidThread()); 435 DCHECK(CalledOnValidThread());
359 UserMediaRequestInfo* request = FindUserMediaRequestInfo(user_media_request); 436 UserMediaRequestInfo* request = FindUserMediaRequestInfo(user_media_request);
360 if (request) { 437 if (request) {
361 // We can't abort the stream generation process. 438 // We can't abort the stream generation process.
362 // Instead, erase the request. Once the stream is generated we will stop the 439 // Instead, erase the request. Once the stream is generated we will stop the
363 // stream if the request does not exist. 440 // stream if the request does not exist.
(...skipping 794 matching lines...) Expand 10 before | Expand all | Expand 10 after
1158 sources_waiting_for_callback_.end(), source); 1235 sources_waiting_for_callback_.end(), source);
1159 if (found != sources_waiting_for_callback_.end()) 1236 if (found != sources_waiting_for_callback_.end())
1160 OnTrackStarted(source, result, result_name); 1237 OnTrackStarted(source, result, result_name);
1161 } 1238 }
1162 1239
1163 void UserMediaClientImpl::OnDestruct() { 1240 void UserMediaClientImpl::OnDestruct() {
1164 delete this; 1241 delete this;
1165 } 1242 }
1166 1243
1167 } // namespace content 1244 } // namespace content
OLDNEW
« no previous file with comments | « content/renderer/media/user_media_client_impl.h ('k') | content/renderer/media/user_media_client_impl_unittest.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698