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
3 // found in the LICENSE file.
5 #include "content/renderer/media/user_media_client_impl.h"
10 #include "base/location.h"
11 #include "base/logging.h"
12 #include "base/single_thread_task_runner.h"
13 #include "base/strings/string_number_conversions.h"
14 #include "base/strings/string_util.h"
15 #include "base/strings/stringprintf.h"
16 #include "base/strings/utf_string_conversions.h"
17 #include "base/thread_task_runner_handle.h"
18 #include "content/public/renderer/render_frame.h"
19 #include "content/renderer/media/media_stream.h"
20 #include "content/renderer/media/media_stream_audio_source.h"
21 #include "content/renderer/media/media_stream_dispatcher.h"
22 #include "content/renderer/media/media_stream_video_capturer_source.h"
23 #include "content/renderer/media/media_stream_video_track.h"
24 #include "content/renderer/media/peer_connection_tracker.h"
25 #include "content/renderer/media/webrtc/webrtc_video_capturer_adapter.h"
26 #include "content/renderer/media/webrtc_audio_capturer.h"
27 #include "content/renderer/media/webrtc_logging.h"
28 #include "content/renderer/media/webrtc_uma_histograms.h"
29 #include "content/renderer/render_thread_impl.h"
30 #include "third_party/WebKit/public/platform/WebMediaConstraints.h"
31 #include "third_party/WebKit/public/platform/WebMediaDeviceInfo.h"
32 #include "third_party/WebKit/public/platform/WebMediaStreamTrack.h"
33 #include "third_party/WebKit/public/platform/WebMediaStreamTrackSourcesRequest.h"
34 #include "third_party/WebKit/public/web/WebDocument.h"
35 #include "third_party/WebKit/public/web/WebLocalFrame.h"
40 void CopyStreamConstraints(const blink::WebMediaConstraints
& constraints
,
41 StreamOptions::Constraints
* mandatory
,
42 StreamOptions::Constraints
* optional
) {
43 blink::WebVector
<blink::WebMediaConstraint
> mandatory_constraints
;
44 constraints
.getMandatoryConstraints(mandatory_constraints
);
45 for (size_t i
= 0; i
< mandatory_constraints
.size(); i
++) {
46 mandatory
->push_back(StreamOptions::Constraint(
47 mandatory_constraints
[i
].m_name
.utf8(),
48 mandatory_constraints
[i
].m_value
.utf8()));
51 blink::WebVector
<blink::WebMediaConstraint
> optional_constraints
;
52 constraints
.getOptionalConstraints(optional_constraints
);
53 for (size_t i
= 0; i
< optional_constraints
.size(); i
++) {
54 optional
->push_back(StreamOptions::Constraint(
55 optional_constraints
[i
].m_name
.utf8(),
56 optional_constraints
[i
].m_value
.utf8()));
60 static int g_next_request_id
= 0;
64 struct UserMediaClientImpl::MediaDevicesRequestInfo
{
65 MediaDevicesRequestInfo(const blink::WebMediaDevicesRequest
& request
,
66 int audio_input_request_id
,
67 int video_input_request_id
,
68 int audio_output_request_id
)
69 : media_devices_request(request
),
70 audio_input_request_id(audio_input_request_id
),
71 video_input_request_id(video_input_request_id
),
72 audio_output_request_id(audio_output_request_id
),
73 has_audio_input_returned(false),
74 has_video_input_returned(false),
75 has_audio_output_returned(false) {}
77 MediaDevicesRequestInfo(
78 const blink::WebMediaStreamTrackSourcesRequest
& request
,
79 int audio_input_request_id
,
80 int video_input_request_id
)
81 : sources_request(request
),
82 audio_input_request_id(audio_input_request_id
),
83 video_input_request_id(video_input_request_id
),
84 audio_output_request_id(-1),
85 has_audio_input_returned(false),
86 has_video_input_returned(false),
87 has_audio_output_returned(false) {}
89 bool IsSourcesRequest() {
90 // We can't check isNull() on |media_devices_request| and |sources_request|,
91 // because in unit tests they will always be null.
92 return audio_output_request_id
== -1;
95 blink::WebMediaDevicesRequest media_devices_request
;
96 blink::WebMediaStreamTrackSourcesRequest sources_request
;
97 int audio_input_request_id
;
98 int video_input_request_id
;
99 int audio_output_request_id
;
100 bool has_audio_input_returned
;
101 bool has_video_input_returned
;
102 bool has_audio_output_returned
;
103 StreamDeviceInfoArray audio_input_devices
;
104 StreamDeviceInfoArray video_input_devices
;
105 StreamDeviceInfoArray audio_output_devices
;
108 UserMediaClientImpl::UserMediaClientImpl(
109 RenderFrame
* render_frame
,
110 PeerConnectionDependencyFactory
* dependency_factory
,
111 scoped_ptr
<MediaStreamDispatcher
> media_stream_dispatcher
)
112 : RenderFrameObserver(render_frame
),
113 dependency_factory_(dependency_factory
),
114 media_stream_dispatcher_(media_stream_dispatcher
.Pass()),
115 weak_factory_(this) {
116 DCHECK(dependency_factory_
);
117 DCHECK(media_stream_dispatcher_
.get());
120 UserMediaClientImpl::~UserMediaClientImpl() {
121 // Force-close all outstanding user media requests and local sources here,
122 // before the outstanding WeakPtrs are invalidated, to ensure a clean
127 void UserMediaClientImpl::requestUserMedia(
128 const blink::WebUserMediaRequest
& user_media_request
) {
129 // Save histogram data so we can see how much GetUserMedia is used.
130 // The histogram counts the number of calls to the JS API
132 UpdateWebRTCMethodCount(WEBKIT_GET_USER_MEDIA
);
133 DCHECK(CalledOnValidThread());
135 if (RenderThreadImpl::current()) {
136 RenderThreadImpl::current()->peer_connection_tracker()->TrackGetUserMedia(
140 int request_id
= g_next_request_id
++;
141 StreamOptions options
;
142 GURL security_origin
;
143 bool enable_automatic_output_device_selection
= false;
145 // |user_media_request| can't be mocked. So in order to test at all we check
147 if (user_media_request
.isNull()) {
149 options
.audio_requested
= true;
150 options
.video_requested
= true;
152 if (user_media_request
.audio()) {
153 options
.audio_requested
= true;
154 CopyStreamConstraints(user_media_request
.audioConstraints(),
155 &options
.mandatory_audio
,
156 &options
.optional_audio
);
158 // Check if this input device should be used to select a matching output
159 // device for audio rendering.
161 if (options
.GetFirstAudioConstraintByName(
162 kMediaStreamRenderToAssociatedSink
, &enable
, NULL
) &&
163 base::LowerCaseEqualsASCII(enable
, "true")) {
164 enable_automatic_output_device_selection
= true;
167 if (user_media_request
.video()) {
168 options
.video_requested
= true;
169 CopyStreamConstraints(user_media_request
.videoConstraints(),
170 &options
.mandatory_video
,
171 &options
.optional_video
);
174 security_origin
= GURL(user_media_request
.securityOrigin().toString());
175 DCHECK(render_frame()->GetWebFrame() ==
176 static_cast<blink::WebFrame
*>(
177 user_media_request
.ownerDocument().frame()));
180 DVLOG(1) << "UserMediaClientImpl::requestUserMedia(" << request_id
<< ", [ "
181 << "audio=" << (options
.audio_requested
)
182 << " select associated sink: "
183 << enable_automatic_output_device_selection
184 << ", video=" << (options
.video_requested
) << " ], "
185 << security_origin
.spec() << ")";
187 std::string audio_device_id
;
188 bool mandatory_audio
;
189 options
.GetFirstAudioConstraintByName(kMediaStreamSourceInfoId
,
190 &audio_device_id
, &mandatory_audio
);
191 std::string video_device_id
;
192 bool mandatory_video
;
193 options
.GetFirstVideoConstraintByName(kMediaStreamSourceInfoId
,
194 &video_device_id
, &mandatory_video
);
196 WebRtcLogMessage(base::StringPrintf(
197 "MSI::requestUserMedia. request_id=%d"
198 ", audio source id=%s mandatory= %s "
199 ", video source id=%s mandatory= %s",
201 audio_device_id
.c_str(),
202 mandatory_audio
? "true":"false",
203 video_device_id
.c_str(),
204 mandatory_video
? "true":"false"));
206 user_media_requests_
.push_back(
207 new UserMediaRequestInfo(request_id
, user_media_request
,
208 enable_automatic_output_device_selection
));
210 base::ThreadTaskRunnerHandle::Get()->PostTask(
211 FROM_HERE
, base::Bind(&UserMediaClientImpl::DelayedRequestUserMedia
,
212 weak_factory_
.GetWeakPtr(), request_id
, options
,
216 void UserMediaClientImpl::DelayedRequestUserMedia(int request_id
,
217 const StreamOptions options
,
218 const GURL security_origin
) {
219 DVLOG(1) << "UserMediaClientImpl::DelayedRequestUserMedia";
220 media_stream_dispatcher_
->GenerateStream(
222 weak_factory_
.GetWeakPtr(),
227 void UserMediaClientImpl::cancelUserMediaRequest(
228 const blink::WebUserMediaRequest
& user_media_request
) {
229 DCHECK(CalledOnValidThread());
230 UserMediaRequestInfo
* request
= FindUserMediaRequestInfo(user_media_request
);
232 // We can't abort the stream generation process.
233 // Instead, erase the request. Once the stream is generated we will stop the
234 // stream if the request does not exist.
235 LogUserMediaRequestWithNoResult(MEDIA_STREAM_REQUEST_EXPLICITLY_CANCELLED
);
236 DeleteUserMediaRequestInfo(request
);
240 void UserMediaClientImpl::requestMediaDevices(
241 const blink::WebMediaDevicesRequest
& media_devices_request
) {
242 UpdateWebRTCMethodCount(WEBKIT_GET_MEDIA_DEVICES
);
243 DCHECK(CalledOnValidThread());
245 int audio_input_request_id
= g_next_request_id
++;
246 int video_input_request_id
= g_next_request_id
++;
247 int audio_output_request_id
= g_next_request_id
++;
249 // |media_devices_request| can't be mocked, so in tests it will be empty (the
250 // underlying pointer is null). In order to use this function in a test we
251 // need to check if it isNull.
252 GURL security_origin
;
253 if (!media_devices_request
.isNull())
254 security_origin
= GURL(media_devices_request
.securityOrigin().toString());
256 DVLOG(1) << "UserMediaClientImpl::requestMediaDevices("
257 << audio_input_request_id
258 << ", " << video_input_request_id
<< ", " << audio_output_request_id
259 << ", " << security_origin
.spec() << ")";
261 media_devices_requests_
.push_back(new MediaDevicesRequestInfo(
262 media_devices_request
,
263 audio_input_request_id
,
264 video_input_request_id
,
265 audio_output_request_id
));
267 media_stream_dispatcher_
->EnumerateDevices(
268 audio_input_request_id
,
269 weak_factory_
.GetWeakPtr(),
270 MEDIA_DEVICE_AUDIO_CAPTURE
,
273 media_stream_dispatcher_
->EnumerateDevices(
274 video_input_request_id
,
275 weak_factory_
.GetWeakPtr(),
276 MEDIA_DEVICE_VIDEO_CAPTURE
,
279 media_stream_dispatcher_
->EnumerateDevices(
280 audio_output_request_id
,
281 weak_factory_
.GetWeakPtr(),
282 MEDIA_DEVICE_AUDIO_OUTPUT
,
286 void UserMediaClientImpl::cancelMediaDevicesRequest(
287 const blink::WebMediaDevicesRequest
& media_devices_request
) {
288 DCHECK(CalledOnValidThread());
289 MediaDevicesRequestInfo
* request
=
290 FindMediaDevicesRequestInfo(media_devices_request
);
293 CancelAndDeleteMediaDevicesRequest(request
);
296 void UserMediaClientImpl::requestSources(
297 const blink::WebMediaStreamTrackSourcesRequest
& sources_request
) {
298 // We don't call UpdateWebRTCMethodCount() here to track the API count in UMA
299 // stats. This is instead counted in MediaStreamTrack::getSources in blink.
300 DCHECK(CalledOnValidThread());
302 int audio_input_request_id
= g_next_request_id
++;
303 int video_input_request_id
= g_next_request_id
++;
305 // |sources_request| can't be mocked, so in tests it will be empty (the
306 // underlying pointer is null). In order to use this function in a test we
307 // need to check if it isNull.
308 GURL security_origin
;
309 if (!sources_request
.isNull())
310 security_origin
= GURL(sources_request
.origin().utf8());
312 DVLOG(1) << "UserMediaClientImpl::requestSources("
313 << audio_input_request_id
314 << ", " << video_input_request_id
315 << ", " << security_origin
.spec() << ")";
317 media_devices_requests_
.push_back(new MediaDevicesRequestInfo(
319 audio_input_request_id
,
320 video_input_request_id
));
322 media_stream_dispatcher_
->EnumerateDevices(
323 audio_input_request_id
,
324 weak_factory_
.GetWeakPtr(),
325 MEDIA_DEVICE_AUDIO_CAPTURE
,
328 media_stream_dispatcher_
->EnumerateDevices(
329 video_input_request_id
,
330 weak_factory_
.GetWeakPtr(),
331 MEDIA_DEVICE_VIDEO_CAPTURE
,
335 // Callback from MediaStreamDispatcher.
336 // The requested stream have been generated by the MediaStreamDispatcher.
337 void UserMediaClientImpl::OnStreamGenerated(
339 const std::string
& label
,
340 const StreamDeviceInfoArray
& audio_array
,
341 const StreamDeviceInfoArray
& video_array
) {
342 DCHECK(CalledOnValidThread());
343 DVLOG(1) << "UserMediaClientImpl::OnStreamGenerated stream:" << label
;
345 UserMediaRequestInfo
* request_info
= FindUserMediaRequestInfo(request_id
);
347 // This can happen if the request is canceled or the frame reloads while
348 // MediaStreamDispatcher is processing the request.
349 DVLOG(1) << "Request ID not found";
350 OnStreamGeneratedForCancelledRequest(audio_array
, video_array
);
353 request_info
->generated
= true;
355 // WebUserMediaRequest don't have an implementation in unit tests.
356 // Therefore we need to check for isNull here and initialize the
358 blink::WebUserMediaRequest
* request
= &(request_info
->request
);
359 blink::WebMediaConstraints audio_constraints
;
360 blink::WebMediaConstraints video_constraints
;
361 if (request
->isNull()) {
362 audio_constraints
.initialize();
363 video_constraints
.initialize();
365 audio_constraints
= request
->audioConstraints();
366 video_constraints
= request
->videoConstraints();
369 blink::WebVector
<blink::WebMediaStreamTrack
> audio_track_vector(
371 CreateAudioTracks(audio_array
, audio_constraints
, &audio_track_vector
,
374 blink::WebVector
<blink::WebMediaStreamTrack
> video_track_vector(
376 CreateVideoTracks(video_array
, video_constraints
, &video_track_vector
,
379 blink::WebString webkit_id
= base::UTF8ToUTF16(label
);
380 blink::WebMediaStream
* web_stream
= &(request_info
->web_stream
);
382 web_stream
->initialize(webkit_id
, audio_track_vector
,
384 web_stream
->setExtraData(
388 // Wait for the tracks to be started successfully or to fail.
389 request_info
->CallbackOnTracksStarted(
390 base::Bind(&UserMediaClientImpl::OnCreateNativeTracksCompleted
,
391 weak_factory_
.GetWeakPtr()));
394 void UserMediaClientImpl::OnStreamGeneratedForCancelledRequest(
395 const StreamDeviceInfoArray
& audio_array
,
396 const StreamDeviceInfoArray
& video_array
) {
397 // Only stop the device if the device is not used in another MediaStream.
398 for (StreamDeviceInfoArray::const_iterator device_it
= audio_array
.begin();
399 device_it
!= audio_array
.end(); ++device_it
) {
400 if (!FindLocalSource(*device_it
))
401 media_stream_dispatcher_
->StopStreamDevice(*device_it
);
404 for (StreamDeviceInfoArray::const_iterator device_it
= video_array
.begin();
405 device_it
!= video_array
.end(); ++device_it
) {
406 if (!FindLocalSource(*device_it
))
407 media_stream_dispatcher_
->StopStreamDevice(*device_it
);
411 void UserMediaClientImpl::FinalizeEnumerateDevices(
412 MediaDevicesRequestInfo
* request
) {
413 // All devices are ready for copying. We use a hashed audio output device id
414 // as the group id for input and output audio devices. If an input device
415 // doesn't have an associated output device, we use the input device's own id.
416 // We don't support group id for video devices, that's left empty.
417 blink::WebVector
<blink::WebMediaDeviceInfo
>
418 devices(request
->audio_input_devices
.size() +
419 request
->video_input_devices
.size() +
420 request
->audio_output_devices
.size());
421 for (size_t i
= 0; i
< request
->audio_input_devices
.size(); ++i
) {
422 const MediaStreamDevice
& device
= request
->audio_input_devices
[i
].device
;
423 DCHECK_EQ(device
.type
, MEDIA_DEVICE_AUDIO_CAPTURE
);
424 std::string group_id
= base::UintToString(base::Hash(
425 !device
.matched_output_device_id
.empty() ?
426 device
.matched_output_device_id
:
428 devices
[i
].initialize(
429 blink::WebString::fromUTF8(device
.id
),
430 blink::WebMediaDeviceInfo::MediaDeviceKindAudioInput
,
431 blink::WebString::fromUTF8(device
.name
),
432 blink::WebString::fromUTF8(group_id
));
434 size_t offset
= request
->audio_input_devices
.size();
435 for (size_t i
= 0; i
< request
->video_input_devices
.size(); ++i
) {
436 const MediaStreamDevice
& device
= request
->video_input_devices
[i
].device
;
437 DCHECK_EQ(device
.type
, MEDIA_DEVICE_VIDEO_CAPTURE
);
438 devices
[offset
+ i
].initialize(
439 blink::WebString::fromUTF8(device
.id
),
440 blink::WebMediaDeviceInfo::MediaDeviceKindVideoInput
,
441 blink::WebString::fromUTF8(device
.name
),
444 offset
+= request
->video_input_devices
.size();
445 for (size_t i
= 0; i
< request
->audio_output_devices
.size(); ++i
) {
446 const MediaStreamDevice
& device
= request
->audio_output_devices
[i
].device
;
447 DCHECK_EQ(device
.type
, MEDIA_DEVICE_AUDIO_OUTPUT
);
448 devices
[offset
+ i
].initialize(
449 blink::WebString::fromUTF8(device
.id
),
450 blink::WebMediaDeviceInfo::MediaDeviceKindAudioOutput
,
451 blink::WebString::fromUTF8(device
.name
),
452 blink::WebString::fromUTF8(base::UintToString(base::Hash(device
.id
))));
455 EnumerateDevicesSucceded(&request
->media_devices_request
, devices
);
458 void UserMediaClientImpl::FinalizeEnumerateSources(
459 MediaDevicesRequestInfo
* request
) {
460 blink::WebVector
<blink::WebSourceInfo
>
461 sources(request
->audio_input_devices
.size() +
462 request
->video_input_devices
.size());
463 for (size_t i
= 0; i
< request
->audio_input_devices
.size(); ++i
) {
464 const MediaStreamDevice
& device
= request
->audio_input_devices
[i
].device
;
465 DCHECK_EQ(device
.type
, MEDIA_DEVICE_AUDIO_CAPTURE
);
466 std::string group_id
= base::UintToString(base::Hash(
467 !device
.matched_output_device_id
.empty() ?
468 device
.matched_output_device_id
:
470 sources
[i
].initialize(blink::WebString::fromUTF8(device
.id
),
471 blink::WebSourceInfo::SourceKindAudio
,
472 blink::WebString::fromUTF8(device
.name
),
473 blink::WebSourceInfo::VideoFacingModeNone
);
475 size_t offset
= request
->audio_input_devices
.size();
476 for (size_t i
= 0; i
< request
->video_input_devices
.size(); ++i
) {
477 const MediaStreamDevice
& device
= request
->video_input_devices
[i
].device
;
478 DCHECK_EQ(device
.type
, MEDIA_DEVICE_VIDEO_CAPTURE
);
479 blink::WebSourceInfo::VideoFacingMode video_facing
;
480 switch (device
.video_facing
) {
481 case MEDIA_VIDEO_FACING_USER
:
482 video_facing
= blink::WebSourceInfo::VideoFacingModeUser
;
484 case MEDIA_VIDEO_FACING_ENVIRONMENT
:
485 video_facing
= blink::WebSourceInfo::VideoFacingModeEnvironment
;
488 video_facing
= blink::WebSourceInfo::VideoFacingModeNone
;
490 sources
[offset
+ i
].initialize(blink::WebString::fromUTF8(device
.id
),
491 blink::WebSourceInfo::SourceKindVideo
,
492 blink::WebString::fromUTF8(device
.name
),
496 EnumerateSourcesSucceded(&request
->sources_request
, sources
);
499 // Callback from MediaStreamDispatcher.
500 // The requested stream failed to be generated.
501 void UserMediaClientImpl::OnStreamGenerationFailed(
503 MediaStreamRequestResult result
) {
504 DCHECK(CalledOnValidThread());
505 DVLOG(1) << "UserMediaClientImpl::OnStreamGenerationFailed("
506 << request_id
<< ")";
507 UserMediaRequestInfo
* request_info
= FindUserMediaRequestInfo(request_id
);
509 // This can happen if the request is canceled or the frame reloads while
510 // MediaStreamDispatcher is processing the request.
511 DVLOG(1) << "Request ID not found";
515 GetUserMediaRequestFailed(request_info
->request
, result
, "");
516 DeleteUserMediaRequestInfo(request_info
);
519 // Callback from MediaStreamDispatcher.
520 // The browser process has stopped a device used by a MediaStream.
521 void UserMediaClientImpl::OnDeviceStopped(
522 const std::string
& label
,
523 const StreamDeviceInfo
& device_info
) {
524 DCHECK(CalledOnValidThread());
525 DVLOG(1) << "UserMediaClientImpl::OnDeviceStopped("
526 << "{device_id = " << device_info
.device
.id
<< "})";
528 const blink::WebMediaStreamSource
* source_ptr
= FindLocalSource(device_info
);
530 // This happens if the same device is used in several guM requests or
531 // if a user happens to stop a track from JS at the same time
532 // as the underlying media device is unplugged from the system.
535 // By creating |source| it is guaranteed that the blink::WebMediaStreamSource
536 // object is valid during the cleanup.
537 blink::WebMediaStreamSource
source(*source_ptr
);
538 StopLocalSource(source
, false);
540 for (LocalStreamSources::iterator device_it
= local_sources_
.begin();
541 device_it
!= local_sources_
.end(); ++device_it
) {
542 if (device_it
->id() == source
.id()) {
543 local_sources_
.erase(device_it
);
549 void UserMediaClientImpl::InitializeSourceObject(
550 const StreamDeviceInfo
& device
,
551 blink::WebMediaStreamSource::Type type
,
552 const blink::WebMediaConstraints
& constraints
,
553 blink::WebMediaStreamSource
* webkit_source
) {
554 const blink::WebMediaStreamSource
* existing_source
=
555 FindLocalSource(device
);
556 if (existing_source
) {
557 *webkit_source
= *existing_source
;
558 DVLOG(1) << "Source already exist. Reusing source with id "
559 << webkit_source
->id().utf8();
563 webkit_source
->initialize(
564 base::UTF8ToUTF16(device
.device
.id
),
566 base::UTF8ToUTF16(device
.device
.name
),
567 false /* remote */, true /* readonly */);
569 DVLOG(1) << "Initialize source object :"
570 << "id = " << webkit_source
->id().utf8()
571 << ", name = " << webkit_source
->name().utf8();
573 if (type
== blink::WebMediaStreamSource::TypeVideo
) {
574 webkit_source
->setExtraData(
577 base::Bind(&UserMediaClientImpl::OnLocalSourceStopped
,
578 weak_factory_
.GetWeakPtr())));
580 DCHECK_EQ(blink::WebMediaStreamSource::TypeAudio
, type
);
581 MediaStreamAudioSource
* audio_source(
582 new MediaStreamAudioSource(
583 RenderFrameObserver::routing_id(),
585 base::Bind(&UserMediaClientImpl::OnLocalSourceStopped
,
586 weak_factory_
.GetWeakPtr()),
587 dependency_factory_
));
588 webkit_source
->setExtraData(audio_source
);
590 local_sources_
.push_back(*webkit_source
);
593 MediaStreamVideoSource
* UserMediaClientImpl::CreateVideoSource(
594 const StreamDeviceInfo
& device
,
595 const MediaStreamSource::SourceStoppedCallback
& stop_callback
) {
596 content::MediaStreamVideoCapturerSource
* ret
=
597 new content::MediaStreamVideoCapturerSource(stop_callback
, device
);
601 void UserMediaClientImpl::CreateVideoTracks(
602 const StreamDeviceInfoArray
& devices
,
603 const blink::WebMediaConstraints
& constraints
,
604 blink::WebVector
<blink::WebMediaStreamTrack
>* webkit_tracks
,
605 UserMediaRequestInfo
* request
) {
606 DCHECK_EQ(devices
.size(), webkit_tracks
->size());
608 for (size_t i
= 0; i
< devices
.size(); ++i
) {
609 blink::WebMediaStreamSource webkit_source
;
610 InitializeSourceObject(devices
[i
],
611 blink::WebMediaStreamSource::TypeVideo
,
614 (*webkit_tracks
)[i
] =
615 request
->CreateAndStartVideoTrack(webkit_source
, constraints
);
619 void UserMediaClientImpl::CreateAudioTracks(
620 const StreamDeviceInfoArray
& devices
,
621 const blink::WebMediaConstraints
& constraints
,
622 blink::WebVector
<blink::WebMediaStreamTrack
>* webkit_tracks
,
623 UserMediaRequestInfo
* request
) {
624 DCHECK_EQ(devices
.size(), webkit_tracks
->size());
626 // Log the device names for this request.
627 for (StreamDeviceInfoArray::const_iterator it
= devices
.begin();
628 it
!= devices
.end(); ++it
) {
629 WebRtcLogMessage(base::StringPrintf(
630 "Generated media stream for request id %d contains audio device name"
633 it
->device
.name
.c_str()));
636 StreamDeviceInfoArray overridden_audio_array
= devices
;
637 if (!request
->enable_automatic_output_device_selection
) {
638 // If the GetUserMedia request did not explicitly set the constraint
639 // kMediaStreamRenderToAssociatedSink, the output device parameters must
641 for (StreamDeviceInfoArray::iterator it
= overridden_audio_array
.begin();
642 it
!= overridden_audio_array
.end(); ++it
) {
643 it
->device
.matched_output_device_id
= "";
644 it
->device
.matched_output
= MediaStreamDevice::AudioDeviceParameters();
648 for (size_t i
= 0; i
< overridden_audio_array
.size(); ++i
) {
649 blink::WebMediaStreamSource webkit_source
;
650 InitializeSourceObject(overridden_audio_array
[i
],
651 blink::WebMediaStreamSource::TypeAudio
,
654 (*webkit_tracks
)[i
].initialize(webkit_source
);
655 request
->StartAudioTrack((*webkit_tracks
)[i
], constraints
);
659 void UserMediaClientImpl::OnCreateNativeTracksCompleted(
660 UserMediaRequestInfo
* request
,
661 MediaStreamRequestResult result
,
662 const blink::WebString
& result_name
) {
663 DVLOG(1) << "UserMediaClientImpl::OnCreateNativeTracksComplete("
664 << "{request_id = " << request
->request_id
<< "} "
665 << "{result = " << result
<< "})";
667 if (result
== content::MEDIA_DEVICE_OK
)
668 GetUserMediaRequestSucceeded(request
->web_stream
, request
->request
);
670 GetUserMediaRequestFailed(request
->request
, result
, result_name
);
672 DeleteUserMediaRequestInfo(request
);
675 void UserMediaClientImpl::OnDevicesEnumerated(
677 const StreamDeviceInfoArray
& device_array
) {
678 DVLOG(1) << "UserMediaClientImpl::OnDevicesEnumerated(" << request_id
<< ")";
680 MediaDevicesRequestInfo
* request
= FindMediaDevicesRequestInfo(request_id
);
683 if (request_id
== request
->audio_input_request_id
) {
684 request
->has_audio_input_returned
= true;
685 DCHECK(request
->audio_input_devices
.empty());
686 request
->audio_input_devices
= device_array
;
687 } else if (request_id
== request
->video_input_request_id
) {
688 request
->has_video_input_returned
= true;
689 DCHECK(request
->video_input_devices
.empty());
690 request
->video_input_devices
= device_array
;
692 DCHECK_EQ(request
->audio_output_request_id
, request_id
);
693 request
->has_audio_output_returned
= true;
694 DCHECK(request
->audio_output_devices
.empty());
695 request
->audio_output_devices
= device_array
;
698 if (!request
->has_audio_input_returned
||
699 !request
->has_video_input_returned
||
700 (!request
->IsSourcesRequest() && !request
->has_audio_output_returned
)) {
701 // Wait for the rest of the devices to complete.
705 if (request
->IsSourcesRequest())
706 FinalizeEnumerateSources(request
);
708 FinalizeEnumerateDevices(request
);
710 CancelAndDeleteMediaDevicesRequest(request
);
713 void UserMediaClientImpl::OnDeviceOpened(
715 const std::string
& label
,
716 const StreamDeviceInfo
& video_device
) {
717 DVLOG(1) << "UserMediaClientImpl::OnDeviceOpened("
718 << request_id
<< ", " << label
<< ")";
722 void UserMediaClientImpl::OnDeviceOpenFailed(int request_id
) {
723 DVLOG(1) << "UserMediaClientImpl::VideoDeviceOpenFailed("
724 << request_id
<< ")";
728 void UserMediaClientImpl::GetUserMediaRequestSucceeded(
729 const blink::WebMediaStream
& stream
,
730 blink::WebUserMediaRequest request_info
) {
731 // Completing the getUserMedia request can lead to that the RenderFrame and
732 // the UserMediaClientImpl is destroyed if the JavaScript code request the
733 // frame to be destroyed within the scope of the callback. Therefore,
734 // post a task to complete the request with a clean stack.
735 base::ThreadTaskRunnerHandle::Get()->PostTask(
737 base::Bind(&UserMediaClientImpl::DelayedGetUserMediaRequestSucceeded
,
738 weak_factory_
.GetWeakPtr(), stream
, request_info
));
741 void UserMediaClientImpl::DelayedGetUserMediaRequestSucceeded(
742 const blink::WebMediaStream
& stream
,
743 blink::WebUserMediaRequest request_info
) {
744 DVLOG(1) << "UserMediaClientImpl::DelayedGetUserMediaRequestSucceeded";
745 LogUserMediaRequestResult(MEDIA_DEVICE_OK
);
746 request_info
.requestSucceeded(stream
);
749 void UserMediaClientImpl::GetUserMediaRequestFailed(
750 blink::WebUserMediaRequest request_info
,
751 MediaStreamRequestResult result
,
752 const blink::WebString
& result_name
) {
753 // Completing the getUserMedia request can lead to that the RenderFrame and
754 // the UserMediaClientImpl is destroyed if the JavaScript code request the
755 // frame to be destroyed within the scope of the callback. Therefore,
756 // post a task to complete the request with a clean stack.
757 base::ThreadTaskRunnerHandle::Get()->PostTask(
759 base::Bind(&UserMediaClientImpl::DelayedGetUserMediaRequestFailed
,
760 weak_factory_
.GetWeakPtr(), request_info
, result
,
764 void UserMediaClientImpl::DelayedGetUserMediaRequestFailed(
765 blink::WebUserMediaRequest request_info
,
766 MediaStreamRequestResult result
,
767 const blink::WebString
& result_name
) {
768 LogUserMediaRequestResult(result
);
770 case MEDIA_DEVICE_OK
:
771 case NUM_MEDIA_REQUEST_RESULTS
:
774 case MEDIA_DEVICE_PERMISSION_DENIED
:
775 request_info
.requestDenied();
777 case MEDIA_DEVICE_PERMISSION_DISMISSED
:
778 request_info
.requestFailedUASpecific("PermissionDismissedError");
780 case MEDIA_DEVICE_INVALID_STATE
:
781 request_info
.requestFailedUASpecific("InvalidStateError");
783 case MEDIA_DEVICE_NO_HARDWARE
:
784 request_info
.requestFailedUASpecific("DevicesNotFoundError");
786 case MEDIA_DEVICE_INVALID_SECURITY_ORIGIN
:
787 request_info
.requestFailedUASpecific("InvalidSecurityOriginError");
789 case MEDIA_DEVICE_TAB_CAPTURE_FAILURE
:
790 request_info
.requestFailedUASpecific("TabCaptureError");
792 case MEDIA_DEVICE_SCREEN_CAPTURE_FAILURE
:
793 request_info
.requestFailedUASpecific("ScreenCaptureError");
795 case MEDIA_DEVICE_CAPTURE_FAILURE
:
796 request_info
.requestFailedUASpecific("DeviceCaptureError");
798 case MEDIA_DEVICE_CONSTRAINT_NOT_SATISFIED
:
799 request_info
.requestFailedConstraint(result_name
);
801 case MEDIA_DEVICE_TRACK_START_FAILURE
:
802 request_info
.requestFailedUASpecific("TrackStartError");
804 case MEDIA_DEVICE_NOT_SUPPORTED
:
805 request_info
.requestFailedUASpecific("MediaDeviceNotSupported");
807 case MEDIA_DEVICE_FAILED_DUE_TO_SHUTDOWN
:
808 request_info
.requestFailedUASpecific("MediaDeviceFailedDueToShutdown");
812 request_info
.requestFailed();
815 void UserMediaClientImpl::EnumerateDevicesSucceded(
816 blink::WebMediaDevicesRequest
* request
,
817 blink::WebVector
<blink::WebMediaDeviceInfo
>& devices
) {
818 request
->requestSucceeded(devices
);
821 void UserMediaClientImpl::EnumerateSourcesSucceded(
822 blink::WebMediaStreamTrackSourcesRequest
* request
,
823 blink::WebVector
<blink::WebSourceInfo
>& sources
) {
824 request
->requestSucceeded(sources
);
827 const blink::WebMediaStreamSource
* UserMediaClientImpl::FindLocalSource(
828 const StreamDeviceInfo
& device
) const {
829 for (LocalStreamSources::const_iterator it
= local_sources_
.begin();
830 it
!= local_sources_
.end(); ++it
) {
831 MediaStreamSource
* const source
=
832 static_cast<MediaStreamSource
*>(it
->extraData());
833 const StreamDeviceInfo
& active_device
= source
->device_info();
834 if (active_device
.device
.id
== device
.device
.id
&&
835 active_device
.device
.type
== device
.device
.type
&&
836 active_device
.session_id
== device
.session_id
) {
843 UserMediaClientImpl::UserMediaRequestInfo
*
844 UserMediaClientImpl::FindUserMediaRequestInfo(int request_id
) {
845 UserMediaRequests::iterator it
= user_media_requests_
.begin();
846 for (; it
!= user_media_requests_
.end(); ++it
) {
847 if ((*it
)->request_id
== request_id
)
853 UserMediaClientImpl::UserMediaRequestInfo
*
854 UserMediaClientImpl::FindUserMediaRequestInfo(
855 const blink::WebUserMediaRequest
& request
) {
856 UserMediaRequests::iterator it
= user_media_requests_
.begin();
857 for (; it
!= user_media_requests_
.end(); ++it
) {
858 if ((*it
)->request
== request
)
864 void UserMediaClientImpl::DeleteUserMediaRequestInfo(
865 UserMediaRequestInfo
* request
) {
866 UserMediaRequests::iterator it
= user_media_requests_
.begin();
867 for (; it
!= user_media_requests_
.end(); ++it
) {
868 if ((*it
) == request
) {
869 user_media_requests_
.erase(it
);
876 void UserMediaClientImpl::DeleteAllUserMediaRequests() {
877 UserMediaRequests::iterator request_it
= user_media_requests_
.begin();
878 while (request_it
!= user_media_requests_
.end()) {
879 DVLOG(1) << "UserMediaClientImpl@" << this
880 << "::DeleteAllUserMediaRequests: "
881 << "Cancel user media request " << (*request_it
)->request_id
;
882 // If the request is not generated, it means that a request
883 // has been sent to the MediaStreamDispatcher to generate a stream
884 // but MediaStreamDispatcher has not yet responded and we need to cancel
886 if (!(*request_it
)->generated
) {
887 DCHECK(!(*request_it
)->HasPendingSources());
888 media_stream_dispatcher_
->CancelGenerateStream(
889 (*request_it
)->request_id
, weak_factory_
.GetWeakPtr());
890 LogUserMediaRequestWithNoResult(MEDIA_STREAM_REQUEST_NOT_GENERATED
);
892 DCHECK((*request_it
)->HasPendingSources());
893 LogUserMediaRequestWithNoResult(
894 MEDIA_STREAM_REQUEST_PENDING_MEDIA_TRACKS
);
896 request_it
= user_media_requests_
.erase(request_it
);
900 UserMediaClientImpl::MediaDevicesRequestInfo
*
901 UserMediaClientImpl::FindMediaDevicesRequestInfo(
903 MediaDevicesRequests::iterator it
= media_devices_requests_
.begin();
904 for (; it
!= media_devices_requests_
.end(); ++it
) {
905 if ((*it
)->audio_input_request_id
== request_id
||
906 (*it
)->video_input_request_id
== request_id
||
907 (*it
)->audio_output_request_id
== request_id
) {
914 UserMediaClientImpl::MediaDevicesRequestInfo
*
915 UserMediaClientImpl::FindMediaDevicesRequestInfo(
916 const blink::WebMediaDevicesRequest
& request
) {
917 MediaDevicesRequests::iterator it
= media_devices_requests_
.begin();
918 for (; it
!= media_devices_requests_
.end(); ++it
) {
919 if ((*it
)->media_devices_request
== request
)
925 void UserMediaClientImpl::CancelAndDeleteMediaDevicesRequest(
926 MediaDevicesRequestInfo
* request
) {
927 MediaDevicesRequests::iterator it
= media_devices_requests_
.begin();
928 for (; it
!= media_devices_requests_
.end(); ++it
) {
929 if ((*it
) == request
) {
930 // Cancel device enumeration.
931 media_stream_dispatcher_
->StopEnumerateDevices(
932 request
->audio_input_request_id
, weak_factory_
.GetWeakPtr());
933 media_stream_dispatcher_
->StopEnumerateDevices(
934 request
->video_input_request_id
, weak_factory_
.GetWeakPtr());
935 media_stream_dispatcher_
->StopEnumerateDevices(
936 request
->audio_output_request_id
, weak_factory_
.GetWeakPtr());
938 media_devices_requests_
.erase(it
);
945 void UserMediaClientImpl::FrameWillClose() {
946 // Cancel all outstanding UserMediaRequests.
947 DeleteAllUserMediaRequests();
949 // Loop through all current local sources and stop the sources.
950 LocalStreamSources::iterator sources_it
= local_sources_
.begin();
951 while (sources_it
!= local_sources_
.end()) {
952 StopLocalSource(*sources_it
, true);
953 sources_it
= local_sources_
.erase(sources_it
);
957 void UserMediaClientImpl::OnLocalSourceStopped(
958 const blink::WebMediaStreamSource
& source
) {
959 DCHECK(CalledOnValidThread());
960 DVLOG(1) << "UserMediaClientImpl::OnLocalSourceStopped";
962 bool device_found
= false;
963 for (LocalStreamSources::iterator device_it
= local_sources_
.begin();
964 device_it
!= local_sources_
.end(); ++device_it
) {
965 if (device_it
->id() == source
.id()) {
967 local_sources_
.erase(device_it
);
973 MediaStreamSource
* source_impl
=
974 static_cast<MediaStreamSource
*>(source
.extraData());
975 media_stream_dispatcher_
->StopStreamDevice(source_impl
->device_info());
978 void UserMediaClientImpl::StopLocalSource(
979 const blink::WebMediaStreamSource
& source
,
980 bool notify_dispatcher
) {
981 MediaStreamSource
* source_impl
=
982 static_cast<MediaStreamSource
*>(source
.extraData());
983 DVLOG(1) << "UserMediaClientImpl::StopLocalSource("
984 << "{device_id = " << source_impl
->device_info().device
.id
<< "})";
986 if (notify_dispatcher
)
987 media_stream_dispatcher_
->StopStreamDevice(source_impl
->device_info());
989 source_impl
->ResetSourceStoppedCallback();
990 source_impl
->StopSource();
993 UserMediaClientImpl::UserMediaRequestInfo::UserMediaRequestInfo(
995 const blink::WebUserMediaRequest
& request
,
996 bool enable_automatic_output_device_selection
)
997 : request_id(request_id
),
999 enable_automatic_output_device_selection(
1000 enable_automatic_output_device_selection
),
1002 request_result_(MEDIA_DEVICE_OK
),
1003 request_result_name_("") {
1006 UserMediaClientImpl::UserMediaRequestInfo::~UserMediaRequestInfo() {
1007 DVLOG(1) << "~UserMediaRequestInfo";
1010 void UserMediaClientImpl::UserMediaRequestInfo::StartAudioTrack(
1011 const blink::WebMediaStreamTrack
& track
,
1012 const blink::WebMediaConstraints
& constraints
) {
1013 DCHECK(track
.source().type() == blink::WebMediaStreamSource::TypeAudio
);
1014 MediaStreamAudioSource
* native_source
=
1015 static_cast <MediaStreamAudioSource
*>(track
.source().extraData());
1016 DCHECK(native_source
);
1018 sources_
.push_back(track
.source());
1019 sources_waiting_for_callback_
.push_back(native_source
);
1020 native_source
->AddTrack(
1021 track
, constraints
, base::Bind(
1022 &UserMediaClientImpl::UserMediaRequestInfo::OnTrackStarted
,
1026 blink::WebMediaStreamTrack
1027 UserMediaClientImpl::UserMediaRequestInfo::CreateAndStartVideoTrack(
1028 const blink::WebMediaStreamSource
& source
,
1029 const blink::WebMediaConstraints
& constraints
) {
1030 DCHECK(source
.type() == blink::WebMediaStreamSource::TypeVideo
);
1031 MediaStreamVideoSource
* native_source
=
1032 MediaStreamVideoSource::GetVideoSource(source
);
1033 DCHECK(native_source
);
1034 sources_
.push_back(source
);
1035 sources_waiting_for_callback_
.push_back(native_source
);
1036 return MediaStreamVideoTrack::CreateVideoTrack(
1037 native_source
, constraints
, base::Bind(
1038 &UserMediaClientImpl::UserMediaRequestInfo::OnTrackStarted
,
1043 void UserMediaClientImpl::UserMediaRequestInfo::CallbackOnTracksStarted(
1044 const ResourcesReady
& callback
) {
1045 DCHECK(ready_callback_
.is_null());
1046 ready_callback_
= callback
;
1047 CheckAllTracksStarted();
1050 void UserMediaClientImpl::UserMediaRequestInfo::OnTrackStarted(
1051 MediaStreamSource
* source
,
1052 MediaStreamRequestResult result
,
1053 const blink::WebString
& result_name
) {
1054 DVLOG(1) << "OnTrackStarted result " << result
;
1055 std::vector
<MediaStreamSource
*>::iterator it
=
1056 std::find(sources_waiting_for_callback_
.begin(),
1057 sources_waiting_for_callback_
.end(),
1059 DCHECK(it
!= sources_waiting_for_callback_
.end());
1060 sources_waiting_for_callback_
.erase(it
);
1061 // All tracks must be started successfully. Otherwise the request is a
1063 if (result
!= MEDIA_DEVICE_OK
) {
1064 request_result_
= result
;
1065 request_result_name_
= result_name
;
1068 CheckAllTracksStarted();
1071 void UserMediaClientImpl::UserMediaRequestInfo::CheckAllTracksStarted() {
1072 if (!ready_callback_
.is_null() && sources_waiting_for_callback_
.empty()) {
1073 ready_callback_
.Run(this, request_result_
, request_result_name_
);
1077 bool UserMediaClientImpl::UserMediaRequestInfo::IsSourceUsed(
1078 const blink::WebMediaStreamSource
& source
) const {
1079 for (std::vector
<blink::WebMediaStreamSource
>::const_iterator source_it
=
1081 source_it
!= sources_
.end(); ++source_it
) {
1082 if (source_it
->id() == source
.id())
1088 void UserMediaClientImpl::UserMediaRequestInfo::RemoveSource(
1089 const blink::WebMediaStreamSource
& source
) {
1090 for (std::vector
<blink::WebMediaStreamSource
>::iterator it
=
1092 it
!= sources_
.end(); ++it
) {
1093 if (source
.id() == it
->id()) {
1100 bool UserMediaClientImpl::UserMediaRequestInfo::HasPendingSources() const {
1101 return !sources_waiting_for_callback_
.empty();
1104 } // namespace content