| 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" | |
| 23 #include "base/threading/thread_task_runner_handle.h" | 21 #include "base/threading/thread_task_runner_handle.h" |
| 24 #include "build/build_config.h" | 22 #include "build/build_config.h" |
| 25 #include "content/public/renderer/render_frame.h" | 23 #include "content/public/renderer/render_frame.h" |
| 26 #include "content/renderer/media/local_media_stream_audio_source.h" | 24 #include "content/renderer/media/local_media_stream_audio_source.h" |
| 27 #include "content/renderer/media/media_stream.h" | 25 #include "content/renderer/media/media_stream.h" |
| 28 #include "content/renderer/media/media_stream_constraints_util.h" | 26 #include "content/renderer/media/media_stream_constraints_util.h" |
| 29 #include "content/renderer/media/media_stream_constraints_util_video_source.h" | |
| 30 #include "content/renderer/media/media_stream_dispatcher.h" | 27 #include "content/renderer/media/media_stream_dispatcher.h" |
| 31 #include "content/renderer/media/media_stream_video_capturer_source.h" | 28 #include "content/renderer/media/media_stream_video_capturer_source.h" |
| 32 #include "content/renderer/media/media_stream_video_track.h" | 29 #include "content/renderer/media/media_stream_video_track.h" |
| 33 #include "content/renderer/media/peer_connection_tracker.h" | 30 #include "content/renderer/media/peer_connection_tracker.h" |
| 34 #include "content/renderer/media/webrtc/processed_local_audio_source.h" | 31 #include "content/renderer/media/webrtc/processed_local_audio_source.h" |
| 35 #include "content/renderer/media/webrtc/webrtc_video_capturer_adapter.h" | 32 #include "content/renderer/media/webrtc/webrtc_video_capturer_adapter.h" |
| 36 #include "content/renderer/media/webrtc_logging.h" | 33 #include "content/renderer/media/webrtc_logging.h" |
| 37 #include "content/renderer/media/webrtc_uma_histograms.h" | 34 #include "content/renderer/media/webrtc_uma_histograms.h" |
| 38 #include "content/renderer/render_thread_impl.h" | 35 #include "content/renderer/render_thread_impl.h" |
| 39 #include "media/capture/video_capture_types.h" | |
| 40 #include "third_party/WebKit/public/platform/URLConversion.h" | 36 #include "third_party/WebKit/public/platform/URLConversion.h" |
| 41 #include "third_party/WebKit/public/platform/WebMediaConstraints.h" | 37 #include "third_party/WebKit/public/platform/WebMediaConstraints.h" |
| 42 #include "third_party/WebKit/public/platform/WebMediaDeviceInfo.h" | 38 #include "third_party/WebKit/public/platform/WebMediaDeviceInfo.h" |
| 43 #include "third_party/WebKit/public/platform/WebMediaStreamTrack.h" | 39 #include "third_party/WebKit/public/platform/WebMediaStreamTrack.h" |
| 44 #include "third_party/WebKit/public/platform/WebString.h" | 40 #include "third_party/WebKit/public/platform/WebString.h" |
| 45 #include "third_party/WebKit/public/web/WebDocument.h" | 41 #include "third_party/WebKit/public/web/WebDocument.h" |
| 46 #include "third_party/WebKit/public/web/WebLocalFrame.h" | 42 #include "third_party/WebKit/public/web/WebLocalFrame.h" |
| 47 #include "third_party/WebKit/public/web/WebUserGestureIndicator.h" | |
| 48 | 43 |
| 49 namespace content { | 44 namespace content { |
| 50 namespace { | 45 namespace { |
| 51 | 46 |
| 52 void CopyFirstString(const blink::StringConstraint& constraint, | 47 void CopyFirstString(const blink::StringConstraint& constraint, |
| 53 std::string* destination) { | 48 std::string* destination) { |
| 54 if (!constraint.exact().isEmpty()) | 49 if (!constraint.exact().isEmpty()) |
| 55 *destination = constraint.exact()[0].utf8(); | 50 *destination = constraint.exact()[0].utf8(); |
| 56 } | 51 } |
| 57 | 52 |
| (...skipping 154 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 212 default: | 207 default: |
| 213 NOTREACHED(); | 208 NOTREACHED(); |
| 214 return blink::WebMediaDeviceInfo::MediaDeviceKindAudioInput; | 209 return blink::WebMediaDeviceInfo::MediaDeviceKindAudioInput; |
| 215 } | 210 } |
| 216 } | 211 } |
| 217 | 212 |
| 218 static int g_next_request_id = 0; | 213 static int g_next_request_id = 0; |
| 219 | 214 |
| 220 } // namespace | 215 } // namespace |
| 221 | 216 |
| 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 | |
| 234 UserMediaClientImpl::UserMediaClientImpl( | 217 UserMediaClientImpl::UserMediaClientImpl( |
| 235 RenderFrame* render_frame, | 218 RenderFrame* render_frame, |
| 236 PeerConnectionDependencyFactory* dependency_factory, | 219 PeerConnectionDependencyFactory* dependency_factory, |
| 237 std::unique_ptr<MediaStreamDispatcher> media_stream_dispatcher, | 220 std::unique_ptr<MediaStreamDispatcher> media_stream_dispatcher) |
| 238 const scoped_refptr<base::TaskRunner>& worker_task_runner) | |
| 239 : RenderFrameObserver(render_frame), | 221 : RenderFrameObserver(render_frame), |
| 240 dependency_factory_(dependency_factory), | 222 dependency_factory_(dependency_factory), |
| 241 media_stream_dispatcher_(std::move(media_stream_dispatcher)), | 223 media_stream_dispatcher_(std::move(media_stream_dispatcher)), |
| 242 worker_task_runner_(worker_task_runner), | |
| 243 weak_factory_(this) { | 224 weak_factory_(this) { |
| 244 DCHECK(dependency_factory_); | 225 DCHECK(dependency_factory_); |
| 245 DCHECK(media_stream_dispatcher_.get()); | 226 DCHECK(media_stream_dispatcher_.get()); |
| 246 } | 227 } |
| 247 | 228 |
| 248 UserMediaClientImpl::~UserMediaClientImpl() { | 229 UserMediaClientImpl::~UserMediaClientImpl() { |
| 249 // Force-close all outstanding user media requests and local sources here, | 230 // Force-close all outstanding user media requests and local sources here, |
| 250 // before the outstanding WeakPtrs are invalidated, to ensure a clean | 231 // before the outstanding WeakPtrs are invalidated, to ensure a clean |
| 251 // shutdown. | 232 // shutdown. |
| 252 WillCommitProvisionalLoad(); | 233 WillCommitProvisionalLoad(); |
| (...skipping 15 matching lines...) Expand all Loading... |
| 268 user_media_request.ownerDocument().frame())); | 249 user_media_request.ownerDocument().frame())); |
| 269 | 250 |
| 270 if (RenderThreadImpl::current()) { | 251 if (RenderThreadImpl::current()) { |
| 271 RenderThreadImpl::current()->peer_connection_tracker()->TrackGetUserMedia( | 252 RenderThreadImpl::current()->peer_connection_tracker()->TrackGetUserMedia( |
| 272 user_media_request); | 253 user_media_request); |
| 273 } | 254 } |
| 274 | 255 |
| 275 int request_id = g_next_request_id++; | 256 int request_id = g_next_request_id++; |
| 276 std::unique_ptr<StreamControls> controls = base::MakeUnique<StreamControls>(); | 257 std::unique_ptr<StreamControls> controls = base::MakeUnique<StreamControls>(); |
| 277 | 258 |
| 278 // The value returned by isProcessingUserGesture() is used by the browser to | 259 bool enable_automatic_output_device_selection = false; |
| 279 // make decisions about the permissions UI. Its value can be lost while | 260 bool request_audio_input_devices = false; |
| 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())); | |
| 284 if (user_media_request.audio()) { | 261 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. | |
| 288 CopyConstraintsToTrackControls(user_media_request.audioConstraints(), | 262 CopyConstraintsToTrackControls(user_media_request.audioConstraints(), |
| 289 &controls->audio, | 263 &controls->audio, |
| 290 &request_audio_input_devices); | 264 &request_audio_input_devices); |
| 291 CopyHotwordAndLocalEchoToStreamControls( | 265 CopyHotwordAndLocalEchoToStreamControls( |
| 292 user_media_request.audioConstraints(), controls.get()); | 266 user_media_request.audioConstraints(), controls.get()); |
| 293 // Check if this input device should be used to select a matching output | 267 // Check if this input device should be used to select a matching output |
| 294 // device for audio rendering. | 268 // device for audio rendering. |
| 295 GetConstraintValueAsBoolean( | 269 GetConstraintValueAsBoolean( |
| 296 user_media_request.audioConstraints(), | 270 user_media_request.audioConstraints(), |
| 297 &blink::WebMediaTrackConstraintSet::renderToAssociatedSink, | 271 &blink::WebMediaTrackConstraintSet::renderToAssociatedSink, |
| 298 &request_settings.enable_automatic_audio_output_device_selection); | 272 &enable_automatic_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 } |
| 299 | 280 |
| 300 if (request_audio_input_devices) { | 281 url::Origin security_origin = user_media_request.getSecurityOrigin(); |
| 301 GetMediaDevicesDispatcher()->EnumerateDevices( | 282 if (request_audio_input_devices || request_video_input_devices) { |
| 302 true /* audio_input */, false /* video_input */, | 283 GetMediaDevicesDispatcher()->EnumerateDevices( |
| 303 false /* audio_output */, request_settings.security_origin, | 284 request_audio_input_devices, request_video_input_devices, |
| 304 base::Bind(&UserMediaClientImpl::SelectAudioInputDevice, | 285 false /* request_audio_output_devices */, security_origin, |
| 305 weak_factory_.GetWeakPtr(), request_id, user_media_request, | 286 base::Bind(&UserMediaClientImpl::SelectUserMediaDevice, |
| 306 base::Passed(&controls), request_settings)); | 287 weak_factory_.GetWeakPtr(), request_id, user_media_request, |
| 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 ""); |
| 307 return; | 313 return; |
| 308 } | 314 } |
| 309 } | 315 } |
| 310 | 316 |
| 311 SetupVideoInput(request_id, user_media_request, std::move(controls), | 317 if (controls->video.requested && |
| 312 request_settings); | 318 IsDeviceSource(controls->video.stream_source)) { |
| 313 } | 319 if (!PickDeviceId(user_media_request.videoConstraints(), |
| 314 | 320 device_enumeration[MEDIA_DEVICE_TYPE_VIDEO_INPUT], |
| 315 void UserMediaClientImpl::SelectAudioInputDevice( | 321 &controls->video.device_id)) { |
| 316 int request_id, | 322 GetUserMediaRequestFailed(user_media_request, MEDIA_DEVICE_NO_HARDWARE, |
| 317 const blink::WebUserMediaRequest& user_media_request, | 323 ""); |
| 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)); | |
| 351 return; | 324 return; |
| 352 } | 325 } |
| 353 } | 326 } |
| 327 |
| 354 FinalizeRequestUserMedia(request_id, user_media_request, std::move(controls), | 328 FinalizeRequestUserMedia(request_id, user_media_request, std::move(controls), |
| 355 request_settings); | 329 enable_automatic_output_device_selection, |
| 356 } | 330 security_origin); |
| 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(); | |
| 405 FinalizeRequestUserMedia(request_id, user_media_request, std::move(controls), | |
| 406 request_settings); | |
| 407 } | 331 } |
| 408 | 332 |
| 409 void UserMediaClientImpl::FinalizeRequestUserMedia( | 333 void UserMediaClientImpl::FinalizeRequestUserMedia( |
| 410 int request_id, | 334 int request_id, |
| 411 const blink::WebUserMediaRequest& user_media_request, | 335 const blink::WebUserMediaRequest& user_media_request, |
| 412 std::unique_ptr<StreamControls> controls, | 336 std::unique_ptr<StreamControls> controls, |
| 413 const RequestSettings& request_settings) { | 337 bool enable_automatic_output_device_selection, |
| 338 const url::Origin& security_origin) { |
| 414 DCHECK(CalledOnValidThread()); | 339 DCHECK(CalledOnValidThread()); |
| 415 | 340 |
| 416 WebRtcLogMessage( | 341 WebRtcLogMessage( |
| 417 base::StringPrintf("MSI::requestUserMedia. request_id=%d" | 342 base::StringPrintf("MSI::requestUserMedia. request_id=%d" |
| 418 ", audio source id=%s" | 343 ", audio source id=%s" |
| 419 ", video source id=%s", | 344 ", video source id=%s", |
| 420 request_id, controls->audio.device_id.c_str(), | 345 request_id, controls->audio.device_id.c_str(), |
| 421 controls->video.device_id.c_str())); | 346 controls->video.device_id.c_str())); |
| 422 | 347 |
| 423 user_media_requests_.push_back(base::MakeUnique<UserMediaRequestInfo>( | 348 user_media_requests_.push_back(std::unique_ptr<UserMediaRequestInfo>( |
| 424 request_id, user_media_request, | 349 new UserMediaRequestInfo(request_id, user_media_request, |
| 425 request_settings.enable_automatic_audio_output_device_selection)); | 350 enable_automatic_output_device_selection))); |
| 426 | 351 |
| 427 media_stream_dispatcher_->GenerateStream( | 352 media_stream_dispatcher_->GenerateStream( |
| 428 request_id, weak_factory_.GetWeakPtr(), *controls, | 353 request_id, weak_factory_.GetWeakPtr(), *controls, security_origin); |
| 429 request_settings.security_origin, | |
| 430 request_settings.is_processing_user_gesture); | |
| 431 } | 354 } |
| 432 | 355 |
| 433 void UserMediaClientImpl::cancelUserMediaRequest( | 356 void UserMediaClientImpl::cancelUserMediaRequest( |
| 434 const blink::WebUserMediaRequest& user_media_request) { | 357 const blink::WebUserMediaRequest& user_media_request) { |
| 435 DCHECK(CalledOnValidThread()); | 358 DCHECK(CalledOnValidThread()); |
| 436 UserMediaRequestInfo* request = FindUserMediaRequestInfo(user_media_request); | 359 UserMediaRequestInfo* request = FindUserMediaRequestInfo(user_media_request); |
| 437 if (request) { | 360 if (request) { |
| 438 // We can't abort the stream generation process. | 361 // We can't abort the stream generation process. |
| 439 // Instead, erase the request. Once the stream is generated we will stop the | 362 // Instead, erase the request. Once the stream is generated we will stop the |
| 440 // stream if the request does not exist. | 363 // stream if the request does not exist. |
| (...skipping 794 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1235 sources_waiting_for_callback_.end(), source); | 1158 sources_waiting_for_callback_.end(), source); |
| 1236 if (found != sources_waiting_for_callback_.end()) | 1159 if (found != sources_waiting_for_callback_.end()) |
| 1237 OnTrackStarted(source, result, result_name); | 1160 OnTrackStarted(source, result, result_name); |
| 1238 } | 1161 } |
| 1239 | 1162 |
| 1240 void UserMediaClientImpl::OnDestruct() { | 1163 void UserMediaClientImpl::OnDestruct() { |
| 1241 delete this; | 1164 delete this; |
| 1242 } | 1165 } |
| 1243 | 1166 |
| 1244 } // namespace content | 1167 } // namespace content |
| OLD | NEW |