| OLD | NEW |
| 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 Loading... |
| 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 Loading... |
| 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 Loading... |
| 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 |
| OLD | NEW |